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