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.jspecify.annotations.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 092public abstract class ComparisonChain { 093 private ComparisonChain() {} 094 095 /** Begins a new chained comparison statement. See example in the class documentation. */ 096 public static ComparisonChain start() { 097 return ACTIVE; 098 } 099 100 private static final ComparisonChain ACTIVE = 101 new ComparisonChain() { 102 @SuppressWarnings("unchecked") // unsafe; see discussion on supertype 103 @Override 104 public ComparisonChain compare(Comparable<?> left, Comparable<?> right) { 105 return classify(((Comparable<Object>) left).compareTo(right)); 106 } 107 108 @Override 109 public <T extends @Nullable Object> ComparisonChain compare( 110 @ParametricNullness T left, @ParametricNullness T right, Comparator<T> comparator) { 111 return classify(comparator.compare(left, right)); 112 } 113 114 @Override 115 public ComparisonChain compare(int left, int right) { 116 return classify(Integer.compare(left, right)); 117 } 118 119 @Override 120 public ComparisonChain compare(long left, long right) { 121 return classify(Long.compare(left, right)); 122 } 123 124 @Override 125 public ComparisonChain compare(float left, float right) { 126 return classify(Float.compare(left, right)); 127 } 128 129 @Override 130 public ComparisonChain compare(double left, double right) { 131 return classify(Double.compare(left, right)); 132 } 133 134 @Override 135 public ComparisonChain compareTrueFirst(boolean left, boolean right) { 136 return classify(Boolean.compare(right, left)); // reversed 137 } 138 139 @Override 140 public ComparisonChain compareFalseFirst(boolean left, boolean right) { 141 return classify(Boolean.compare(left, right)); 142 } 143 144 ComparisonChain classify(int result) { 145 return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE; 146 } 147 148 @Override 149 public int result() { 150 return 0; 151 } 152 }; 153 154 private static final ComparisonChain LESS = new InactiveComparisonChain(-1); 155 156 private static final ComparisonChain GREATER = new InactiveComparisonChain(1); 157 158 private static final class InactiveComparisonChain extends ComparisonChain { 159 final int result; 160 161 InactiveComparisonChain(int result) { 162 this.result = result; 163 } 164 165 @Override 166 public ComparisonChain compare(Comparable<?> left, Comparable<?> right) { 167 return this; 168 } 169 170 @Override 171 public <T extends @Nullable Object> ComparisonChain compare( 172 @ParametricNullness T left, @ParametricNullness T right, Comparator<T> comparator) { 173 return this; 174 } 175 176 @Override 177 public ComparisonChain compare(int left, int right) { 178 return this; 179 } 180 181 @Override 182 public ComparisonChain compare(long left, long right) { 183 return this; 184 } 185 186 @Override 187 public ComparisonChain compare(float left, float right) { 188 return this; 189 } 190 191 @Override 192 public ComparisonChain compare(double left, double right) { 193 return this; 194 } 195 196 @Override 197 public ComparisonChain compareTrueFirst(boolean left, boolean right) { 198 return this; 199 } 200 201 @Override 202 public ComparisonChain compareFalseFirst(boolean left, boolean right) { 203 return this; 204 } 205 206 @Override 207 public int result() { 208 return result; 209 } 210 } 211 212 /** 213 * Compares two comparable objects as specified by {@link Comparable#compareTo}, <i>if</i> the 214 * result of this comparison chain has not already been determined. 215 * 216 * <p>This method is declared to accept any 2 {@code Comparable} objects, even if they are not <a 217 * href="https://docs.oracle.com/javase/tutorial/collections/interfaces/order.html">mutually 218 * comparable</a>. If you pass objects that are not mutually comparable, this method may throw an 219 * exception. (The reason for this decision is lost to time, but the reason <i>might</i> be that 220 * we wanted to support legacy classes that implement the raw type {@code Comparable} (instead of 221 * implementing {@code Comparable<Foo>}) without producing warnings. If so, we would prefer today 222 * to produce warnings in that case, and we may change this method to do so in the future. Support 223 * for raw {@code Comparable} types in Guava in general is tracked as <a 224 * href="https://github.com/google/guava/issues/989">#989</a>.) 225 * 226 * @throws ClassCastException if the parameters are not mutually comparable 227 */ 228 public abstract ComparisonChain compare(Comparable<?> left, Comparable<?> right); 229 230 /** 231 * Compares two objects using a comparator, <i>if</i> the result of this comparison chain has not 232 * already been determined. 233 */ 234 public abstract <T extends @Nullable Object> ComparisonChain compare( 235 @ParametricNullness T left, @ParametricNullness T right, Comparator<T> comparator); 236 237 /** 238 * Compares two {@code int} values as specified by {@link Integer#compare}, <i>if</i> the result 239 * of this comparison chain has not already been determined. 240 */ 241 public abstract ComparisonChain compare(int left, int right); 242 243 /** 244 * Compares two {@code long} values as specified by {@link Long#compare}, <i>if</i> the result of 245 * this comparison chain has not already been determined. 246 */ 247 public abstract ComparisonChain compare(long left, long right); 248 249 /** 250 * Compares two {@code float} values as specified by {@link Float#compare}, <i>if</i> the result 251 * of this comparison chain has not already been determined. 252 */ 253 public abstract ComparisonChain compare(float left, float right); 254 255 /** 256 * Compares two {@code double} values as specified by {@link Double#compare}, <i>if</i> the result 257 * of this comparison chain has not already been determined. 258 */ 259 public abstract ComparisonChain compare(double left, double right); 260 261 /** 262 * Discouraged synonym for {@link #compareFalseFirst}. 263 * 264 * @deprecated Use {@link #compareFalseFirst}; or, if the parameters passed are being either 265 * negated or reversed, undo the negation or reversal and use {@link #compareTrueFirst}. 266 * @since 19.0 267 */ 268 @Deprecated 269 public final ComparisonChain compare(Boolean left, Boolean right) { 270 return compareFalseFirst(left, right); 271 } 272 273 /** 274 * Compares two {@code boolean} values, considering {@code true} to be less than {@code false}, 275 * <i>if</i> the result of this comparison chain has not already been determined. 276 * 277 * <p>Java 8+ users: you can get the equivalent from {@link Booleans#trueFirst()}. For example: 278 * 279 * <pre> 280 * Comparator.comparing(Foo::isBar, {@link Booleans#trueFirst()}) 281 * </pre> 282 * 283 * @since 12.0 284 */ 285 public abstract ComparisonChain compareTrueFirst(boolean left, boolean right); 286 287 /** 288 * Compares two {@code boolean} values, considering {@code false} to be less than {@code true}, 289 * <i>if</i> the result of this comparison chain has not already been determined. 290 * 291 * <p>Java 8+ users: you can get the equivalent from {@link Booleans#falseFirst()}. For example: 292 * 293 * <pre> 294 * Comparator.comparing(Foo::isBar, {@link Booleans#falseFirst()}) 295 * </pre> 296 * 297 * @since 12.0 (present as {@code compare} since 2.0) 298 */ 299 public abstract ComparisonChain compareFalseFirst(boolean left, boolean right); 300 301 /** 302 * Ends this comparison chain and returns its result: a value having the same sign as the first 303 * nonzero comparison result in the chain, or zero if every result was zero. 304 */ 305 public abstract int result(); 306}