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