001/* 002 * Copyright (C) 2009 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect; 018 019import com.google.common.annotations.GwtCompatible; 020import com.google.common.primitives.Booleans; 021import com.google.common.primitives.Ints; 022import com.google.common.primitives.Longs; 023 024import java.util.Comparator; 025 026import javax.annotation.Nullable; 027 028/** 029 * A utility for performing a chained comparison statement. For example: 030 * <pre> {@code 031 * 032 * public int compareTo(Foo that) { 033 * return ComparisonChain.start() 034 * .compare(this.aString, that.aString) 035 * .compare(this.anInt, that.anInt) 036 * .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast()) 037 * .result(); 038 * }}</pre> 039 * 040 * <p>The value of this expression will have the same sign as the <i>first 041 * nonzero</i> comparison result in the chain, or will be zero if every 042 * comparison result was zero. 043 * 044 * <p>Performance note: Even though the {@code ComparisonChain} caller always 045 * invokes its {@code compare} methods unconditionally, the {@code 046 * ComparisonChain} implementation stops calling its inputs' {@link 047 * Comparable#compareTo compareTo} and {@link Comparator#compare compare} 048 * methods as soon as one of them returns a nonzero result. This optimization is 049 * typically important only in the presence of expensive {@code compareTo} and 050 * {@code compare} implementations. 051 * 052 * <p>See the Guava User Guide article on <a href= 053 * "http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained#compare/compareTo"> 054 * {@code ComparisonChain}</a>. 055 * 056 * @author Mark Davis 057 * @author Kevin Bourrillion 058 * @since 2.0 059 */ 060@GwtCompatible 061public abstract class ComparisonChain { 062 private ComparisonChain() {} 063 064 /** 065 * Begins a new chained comparison statement. See example in the class 066 * documentation. 067 */ 068 public static ComparisonChain start() { 069 return ACTIVE; 070 } 071 072 private static final ComparisonChain ACTIVE = new ComparisonChain() { 073 @SuppressWarnings("unchecked") 074 @Override public ComparisonChain compare( 075 Comparable left, Comparable right) { 076 return classify(left.compareTo(right)); 077 } 078 @Override public <T> ComparisonChain compare( 079 @Nullable T left, @Nullable T right, Comparator<T> comparator) { 080 return classify(comparator.compare(left, right)); 081 } 082 @Override public ComparisonChain compare(int left, int right) { 083 return classify(Ints.compare(left, right)); 084 } 085 @Override public ComparisonChain compare(long left, long right) { 086 return classify(Longs.compare(left, right)); 087 } 088 @Override public ComparisonChain compare(float left, float right) { 089 return classify(Float.compare(left, right)); 090 } 091 @Override public ComparisonChain compare(double left, double right) { 092 return classify(Double.compare(left, right)); 093 } 094 @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) { 095 return classify(Booleans.compare(right, left)); // reversed 096 } 097 @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) { 098 return classify(Booleans.compare(left, right)); 099 } 100 ComparisonChain classify(int result) { 101 return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE; 102 } 103 @Override public int result() { 104 return 0; 105 } 106 }; 107 108 private static final ComparisonChain LESS = new InactiveComparisonChain(-1); 109 110 private static final ComparisonChain GREATER = new InactiveComparisonChain(1); 111 112 private static final class InactiveComparisonChain extends ComparisonChain { 113 final int result; 114 115 InactiveComparisonChain(int result) { 116 this.result = result; 117 } 118 @Override public ComparisonChain compare( 119 @Nullable Comparable left, @Nullable Comparable right) { 120 return this; 121 } 122 @Override public <T> ComparisonChain compare(@Nullable T left, 123 @Nullable T right, @Nullable Comparator<T> comparator) { 124 return this; 125 } 126 @Override public ComparisonChain compare(int left, int right) { 127 return this; 128 } 129 @Override public ComparisonChain compare(long left, long right) { 130 return this; 131 } 132 @Override public ComparisonChain compare(float left, float right) { 133 return this; 134 } 135 @Override public ComparisonChain compare(double left, double right) { 136 return this; 137 } 138 @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) { 139 return this; 140 } 141 @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) { 142 return this; 143 } 144 @Override public int result() { 145 return result; 146 } 147 } 148 149 /** 150 * Compares two comparable objects as specified by {@link 151 * Comparable#compareTo}, <i>if</i> the result of this comparison chain 152 * has not already been determined. 153 */ 154 public abstract ComparisonChain compare( 155 Comparable<?> left, Comparable<?> right); 156 157 /** 158 * Compares two objects using a comparator, <i>if</i> the result of this 159 * comparison chain has not already been determined. 160 */ 161 public abstract <T> ComparisonChain compare( 162 @Nullable T left, @Nullable T right, Comparator<T> comparator); 163 164 /** 165 * Compares two {@code int} values as specified by {@link Ints#compare}, 166 * <i>if</i> the result of this comparison chain has not already been 167 * determined. 168 */ 169 public abstract ComparisonChain compare(int left, int right); 170 171 /** 172 * Compares two {@code long} values as specified by {@link Longs#compare}, 173 * <i>if</i> the result of this comparison chain has not already been 174 * determined. 175 */ 176 public abstract ComparisonChain compare(long left, long right); 177 178 /** 179 * Compares two {@code float} values as specified by {@link 180 * Float#compare}, <i>if</i> the result of this comparison chain has not 181 * already been determined. 182 */ 183 public abstract ComparisonChain compare(float left, float right); 184 185 /** 186 * Compares two {@code double} values as specified by {@link 187 * Double#compare}, <i>if</i> the result of this comparison chain has not 188 * already been determined. 189 */ 190 public abstract ComparisonChain compare(double left, double right); 191 192 /** 193 * Compares two {@code boolean} values, considering {@code true} to be less 194 * than {@code false}, <i>if</i> the result of this comparison chain has not 195 * already been determined. 196 * 197 * @since 12.0 198 */ 199 public abstract ComparisonChain compareTrueFirst(boolean left, boolean right); 200 201 /** 202 * Compares two {@code boolean} values, considering {@code false} to be less 203 * than {@code true}, <i>if</i> the result of this comparison chain has not 204 * already been determined. 205 * 206 * @since 12.0 (present as {@code compare} since 2.0) 207 */ 208 public abstract ComparisonChain compareFalseFirst(boolean left, boolean right); 209 210 /** 211 * Old name of {@link #compareFalseFirst}. 212 * 213 * @deprecated Use {@link #compareFalseFirst}; or, if the parameters passed 214 * are being either negated or reversed, undo the negation or reversal and 215 * use {@link #compareTrueFirst}. <b>This method is scheduled for deletion 216 * in September 2013.</b> 217 */ 218 @Deprecated 219 public final ComparisonChain compare(boolean left, boolean right) { 220 return compareFalseFirst(left, right); 221 } 222 223 /** 224 * Ends this comparison chain and returns its result: a value having the 225 * same sign as the first nonzero comparison result in the chain, or zero if 226 * every result was zero. 227 */ 228 public abstract int result(); 229}