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; 023import java.util.Comparator; 024import org.checkerframework.checker.nullness.qual.Nullable; 025 026/** 027 * A utility for performing a chained comparison statement. <b>Note:</b> Java 8+ users should 028 * generally prefer the methods in {@link Comparator}; see <a href="#java8">below</a>. 029 * 030 * <p>Example usage of {@code ComparisonChain}: 031 * 032 * <pre>{@code 033 * public int compareTo(Foo that) { 034 * return ComparisonChain.start() 035 * .compare(this.aString, that.aString) 036 * .compare(this.anInt, that.anInt) 037 * .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast()) 038 * .result(); 039 * } 040 * }</pre> 041 * 042 * <p>The value of this expression will have the same sign as the <i>first nonzero</i> comparison 043 * result in the chain, or will be zero if every comparison result was zero. 044 * 045 * <p><b>Note:</b> {@code ComparisonChain} instances are <b>immutable</b>. For this utility to work 046 * correctly, calls must be chained as illustrated above. 047 * 048 * <p>Performance note: Even though the {@code ComparisonChain} caller always invokes its {@code 049 * compare} methods unconditionally, the {@code ComparisonChain} implementation stops calling its 050 * inputs' {@link Comparable#compareTo compareTo} and {@link Comparator#compare compare} methods as 051 * soon as one of them returns a nonzero result. This optimization is typically important only in 052 * the presence of expensive {@code compareTo} and {@code compare} implementations. 053 * 054 * <p>See the Guava User Guide article on <a href= 055 * "https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained#comparecompareto">{@code 056 * ComparisonChain}</a>. 057 * 058 * <h4 id="java8">Java 8+ equivalents</h4> 059 * 060 * If you are using Java version 8 or greater, you should generally use the static methods in {@link 061 * Comparator} instead of {@code ComparisonChain}. The example above can be implemented like this: 062 * 063 * <pre>{@code 064 * import static java.util.Comparator.comparing; 065 * import static java.util.Comparator.nullsLast; 066 * import static java.util.Comparator.naturalOrder; 067 * 068 * ... 069 * private static final Comparator<Foo> COMPARATOR = 070 * comparing((Foo foo) -> foo.aString) 071 * .thenComparing(foo -> foo.anInt) 072 * .thenComparing(foo -> foo.anEnum, nullsLast(naturalOrder()));} 073 * 074 * {@code @Override}{@code 075 * public int compareTo(Foo that) { 076 * return COMPARATOR.compare(this, that); 077 * } 078 * }</pre> 079 * 080 * <p>With method references it is more succinct: {@code comparing(Foo::aString)} for example. 081 * 082 * <p>Using {@link Comparator} avoids certain types of bugs, for example when you meant to write 083 * {@code .compare(a.foo, b.foo)} but you actually wrote {@code .compare(a.foo, a.foo)} or {@code 084 * .compare(a.foo, b.bar)}. {@code ComparisonChain} also has a potential performance problem that 085 * {@code Comparator} doesn't: it evaluates all the parameters of all the {@code .compare} calls, 086 * even when the result of the comparison is already known from previous {@code .compare} calls. 087 * That can be expensive. 088 * 089 * @author Mark Davis 090 * @author Kevin Bourrillion 091 * @since 2.0 092 */ 093@GwtCompatible 094@ElementTypesAreNonnullByDefault 095public abstract class ComparisonChain { 096 private ComparisonChain() {} 097 098 /** Begins a new chained comparison statement. See example in the class documentation. */ 099 public static ComparisonChain start() { 100 return ACTIVE; 101 } 102 103 private static final ComparisonChain ACTIVE = 104 new ComparisonChain() { 105 @SuppressWarnings("unchecked") // unsafe; see discussion on supertype 106 @Override 107 public ComparisonChain compare(Comparable<?> left, Comparable<?> right) { 108 return classify(((Comparable<Object>) left).compareTo(right)); 109 } 110 111 @Override 112 public <T extends @Nullable Object> ComparisonChain compare( 113 @ParametricNullness T left, @ParametricNullness T right, Comparator<T> comparator) { 114 return classify(comparator.compare(left, right)); 115 } 116 117 @Override 118 public ComparisonChain compare(int left, int right) { 119 return classify(Ints.compare(left, right)); 120 } 121 122 @Override 123 public ComparisonChain compare(long left, long right) { 124 return classify(Longs.compare(left, right)); 125 } 126 127 @Override 128 public ComparisonChain compare(float left, float right) { 129 return classify(Float.compare(left, right)); 130 } 131 132 @Override 133 public ComparisonChain compare(double left, double right) { 134 return classify(Double.compare(left, right)); 135 } 136 137 @Override 138 public ComparisonChain compareTrueFirst(boolean left, boolean right) { 139 return classify(Booleans.compare(right, left)); // reversed 140 } 141 142 @Override 143 public ComparisonChain compareFalseFirst(boolean left, boolean right) { 144 return classify(Booleans.compare(left, right)); 145 } 146 147 ComparisonChain classify(int result) { 148 return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE; 149 } 150 151 @Override 152 public int result() { 153 return 0; 154 } 155 }; 156 157 private static final ComparisonChain LESS = new InactiveComparisonChain(-1); 158 159 private static final ComparisonChain GREATER = new InactiveComparisonChain(1); 160 161 private static final class InactiveComparisonChain extends ComparisonChain { 162 final int result; 163 164 InactiveComparisonChain(int result) { 165 this.result = result; 166 } 167 168 @Override 169 public ComparisonChain compare(Comparable<?> left, Comparable<?> right) { 170 return this; 171 } 172 173 @Override 174 public <T extends @Nullable Object> ComparisonChain compare( 175 @ParametricNullness T left, @ParametricNullness T right, Comparator<T> comparator) { 176 return this; 177 } 178 179 @Override 180 public ComparisonChain compare(int left, int right) { 181 return this; 182 } 183 184 @Override 185 public ComparisonChain compare(long left, long right) { 186 return this; 187 } 188 189 @Override 190 public ComparisonChain compare(float left, float right) { 191 return this; 192 } 193 194 @Override 195 public ComparisonChain compare(double left, double right) { 196 return this; 197 } 198 199 @Override 200 public ComparisonChain compareTrueFirst(boolean left, boolean right) { 201 return this; 202 } 203 204 @Override 205 public ComparisonChain compareFalseFirst(boolean left, boolean right) { 206 return this; 207 } 208 209 @Override 210 public int result() { 211 return result; 212 } 213 } 214 215 /** 216 * Compares two comparable objects as specified by {@link Comparable#compareTo}, <i>if</i> the 217 * result of this comparison chain has not already been determined. 218 * 219 * <p>This method is declared to accept any 2 {@code Comparable} objects, even if they are not <a 220 * href="https://docs.oracle.com/javase/tutorial/collections/interfaces/order.html">mutually 221 * comparable</a>. If you pass objects that are not mutually comparable, this method may throw an 222 * exception. (The reason for this decision is lost to time, but the reason <i>might</i> be that 223 * we wanted to support legacy classes that implement the raw type {@code Comparable} (instead of 224 * implementing {@code Comparable<Foo>}) without producing warnings. If so, we would prefer today 225 * to produce warnings in that case, and we may change this method to do so in the future. Support 226 * for raw {@code Comparable} types in Guava in general is tracked as <a 227 * href="https://github.com/google/guava/issues/989">#989</a>.) 228 * 229 * @throws ClassCastException if the parameters are not mutually comparable 230 */ 231 public abstract ComparisonChain compare(Comparable<?> left, Comparable<?> right); 232 233 /** 234 * Compares two objects using a comparator, <i>if</i> the result of this comparison chain has not 235 * already been determined. 236 */ 237 public abstract <T extends @Nullable Object> ComparisonChain compare( 238 @ParametricNullness T left, @ParametricNullness T right, Comparator<T> comparator); 239 240 /** 241 * Compares two {@code int} values as specified by {@link Ints#compare}, <i>if</i> the result of 242 * this comparison chain has not already been determined. 243 */ 244 public abstract ComparisonChain compare(int left, int right); 245 246 /** 247 * Compares two {@code long} values as specified by {@link Longs#compare}, <i>if</i> the result of 248 * this comparison chain has not already been determined. 249 */ 250 public abstract ComparisonChain compare(long left, long right); 251 252 /** 253 * Compares two {@code float} values as specified by {@link Float#compare}, <i>if</i> the result 254 * of this comparison chain has not already been determined. 255 */ 256 public abstract ComparisonChain compare(float left, float right); 257 258 /** 259 * Compares two {@code double} values as specified by {@link Double#compare}, <i>if</i> the result 260 * of this comparison chain has not already been determined. 261 */ 262 public abstract ComparisonChain compare(double left, double right); 263 264 /** 265 * Discouraged synonym for {@link #compareFalseFirst}. 266 * 267 * @deprecated Use {@link #compareFalseFirst}; or, if the parameters passed are being either 268 * negated or reversed, undo the negation or reversal and use {@link #compareTrueFirst}. 269 * @since 19.0 270 */ 271 @Deprecated 272 public final ComparisonChain compare(Boolean left, Boolean right) { 273 return compareFalseFirst(left, right); 274 } 275 276 /** 277 * Compares two {@code boolean} values, considering {@code true} to be less than {@code false}, 278 * <i>if</i> the result of this comparison chain has not already been determined. 279 * 280 * <p>Java 8+ users: you can get the equivalent from {@link Booleans#trueFirst()}. For example: 281 * 282 * <pre> 283 * Comparator.comparing(Foo::isBar, {@link Booleans#trueFirst()}) 284 * </pre> 285 * 286 * @since 12.0 287 */ 288 public abstract ComparisonChain compareTrueFirst(boolean left, boolean right); 289 290 /** 291 * Compares two {@code boolean} values, considering {@code false} to be less than {@code true}, 292 * <i>if</i> the result of this comparison chain has not already been determined. 293 * 294 * <p>Java 8+ users: you can get the equivalent from {@link Booleans#falseFirst()}. For example: 295 * 296 * <pre> 297 * Comparator.comparing(Foo::isBar, {@link Booleans#falseFirst()}) 298 * </pre> 299 * 300 * @since 12.0 (present as {@code compare} since 2.0) 301 */ 302 public abstract ComparisonChain compareFalseFirst(boolean left, boolean right); 303 304 /** 305 * Ends this comparison chain and returns its result: a value having the same sign as the first 306 * nonzero comparison result in the chain, or zero if every result was zero. 307 */ 308 public abstract int result(); 309}