1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.base; 18 19 import com.google.common.annotations.GwtCompatible; 20 import com.google.common.annotations.VisibleForTesting; 21 22 import java.util.NoSuchElementException; 23 24 import javax.annotation.Nullable; 25 26 /** 27 * Simple static methods to be called at the start of your own methods to verify 28 * correct arguments and state. This allows constructs such as 29 * <pre> 30 * if (count <= 0) { 31 * throw new IllegalArgumentException("must be positive: " + count); 32 * }</pre> 33 * 34 * to be replaced with the more compact 35 * <pre> 36 * checkArgument(count > 0, "must be positive: %s", count);</pre> 37 * 38 * Note that the sense of the expression is inverted; with {@code Preconditions} 39 * you declare what you expect to be <i>true</i>, just as you do with an 40 * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html"> 41 * {@code assert}</a> or a JUnit {@code assertTrue} call. 42 * 43 * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a 44 * placeholder in these messages, not the full range of {@link 45 * String#format(String, Object[])} specifiers. 46 * 47 * <p>Take care not to confuse precondition checking with other similar types 48 * of checks! Precondition exceptions -- including those provided here, but also 49 * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link 50 * UnsupportedOperationException} and others -- are used to signal that the 51 * <i>calling method</i> has made an error. This tells the caller that it should 52 * not have invoked the method when it did, with the arguments it did, or 53 * perhaps ever. Postcondition or other invariant failures should not throw 54 * these types of exceptions. 55 * 56 * @author Kevin Bourrillion 57 * @since 2.0 (imported from Google Collections Library) 58 */ 59 @GwtCompatible 60 public final class Preconditions { Preconditions()61 private Preconditions() {} 62 63 /** 64 * Ensures the truth of an expression involving one or more parameters to the 65 * calling method. 66 * 67 * @param expression a boolean expression 68 * @throws IllegalArgumentException if {@code expression} is false 69 */ checkArgument(boolean expression)70 public static void checkArgument(boolean expression) { 71 if (!expression) { 72 throw new IllegalArgumentException(); 73 } 74 } 75 76 /** 77 * Ensures the truth of an expression involving one or more parameters to the 78 * calling method. 79 * 80 * @param expression a boolean expression 81 * @param errorMessage the exception message to use if the check fails; will 82 * be converted to a string using {@link String#valueOf(Object)} 83 * @throws IllegalArgumentException if {@code expression} is false 84 */ checkArgument( boolean expression, @Nullable Object errorMessage)85 public static void checkArgument( 86 boolean expression, @Nullable Object errorMessage) { 87 if (!expression) { 88 throw new IllegalArgumentException(String.valueOf(errorMessage)); 89 } 90 } 91 92 /** 93 * Ensures the truth of an expression involving one or more parameters to the 94 * calling method. 95 * 96 * @param expression a boolean expression 97 * @param errorMessageTemplate a template for the exception message should the 98 * check fail. The message is formed by replacing each {@code %s} 99 * placeholder in the template with an argument. These are matched by 100 * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 101 * Unmatched arguments will be appended to the formatted message in square 102 * braces. Unmatched placeholders will be left as-is. 103 * @param errorMessageArgs the arguments to be substituted into the message 104 * template. Arguments are converted to strings using 105 * {@link String#valueOf(Object)}. 106 * @throws IllegalArgumentException if {@code expression} is false 107 * @throws NullPointerException if the check fails and either {@code 108 * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let 109 * this happen) 110 */ checkArgument(boolean expression, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs)111 public static void checkArgument(boolean expression, 112 @Nullable String errorMessageTemplate, 113 @Nullable Object... errorMessageArgs) { 114 if (!expression) { 115 throw new IllegalArgumentException( 116 format(errorMessageTemplate, errorMessageArgs)); 117 } 118 } 119 120 /** 121 * Ensures the truth of an expression involving the state of the calling 122 * instance, but not involving any parameters to the calling method. 123 * 124 * @param expression a boolean expression 125 * @throws IllegalStateException if {@code expression} is false 126 */ checkState(boolean expression)127 public static void checkState(boolean expression) { 128 if (!expression) { 129 throw new IllegalStateException(); 130 } 131 } 132 133 /** 134 * Ensures the truth of an expression involving the state of the calling 135 * instance, but not involving any parameters to the calling method. 136 * 137 * @param expression a boolean expression 138 * @param errorMessage the exception message to use if the check fails; will 139 * be converted to a string using {@link String#valueOf(Object)} 140 * @throws IllegalStateException if {@code expression} is false 141 */ checkState( boolean expression, @Nullable Object errorMessage)142 public static void checkState( 143 boolean expression, @Nullable Object errorMessage) { 144 if (!expression) { 145 throw new IllegalStateException(String.valueOf(errorMessage)); 146 } 147 } 148 149 /** 150 * Ensures the truth of an expression involving the state of the calling 151 * instance, but not involving any parameters to the calling method. 152 * 153 * @param expression a boolean expression 154 * @param errorMessageTemplate a template for the exception message should the 155 * check fail. The message is formed by replacing each {@code %s} 156 * placeholder in the template with an argument. These are matched by 157 * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 158 * Unmatched arguments will be appended to the formatted message in square 159 * braces. Unmatched placeholders will be left as-is. 160 * @param errorMessageArgs the arguments to be substituted into the message 161 * template. Arguments are converted to strings using 162 * {@link String#valueOf(Object)}. 163 * @throws IllegalStateException if {@code expression} is false 164 * @throws NullPointerException if the check fails and either {@code 165 * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let 166 * this happen) 167 */ checkState(boolean expression, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs)168 public static void checkState(boolean expression, 169 @Nullable String errorMessageTemplate, 170 @Nullable Object... errorMessageArgs) { 171 if (!expression) { 172 throw new IllegalStateException( 173 format(errorMessageTemplate, errorMessageArgs)); 174 } 175 } 176 177 /** 178 * Ensures that an object reference passed as a parameter to the calling 179 * method is not null. 180 * 181 * @param reference an object reference 182 * @return the non-null reference that was validated 183 * @throws NullPointerException if {@code reference} is null 184 */ checkNotNull(T reference)185 public static <T> T checkNotNull(T reference) { 186 if (reference == null) { 187 throw new NullPointerException(); 188 } 189 return reference; 190 } 191 192 /** 193 * Ensures that an object reference passed as a parameter to the calling 194 * method is not null. 195 * 196 * @param reference an object reference 197 * @param errorMessage the exception message to use if the check fails; will 198 * be converted to a string using {@link String#valueOf(Object)} 199 * @return the non-null reference that was validated 200 * @throws NullPointerException if {@code reference} is null 201 */ checkNotNull(T reference, @Nullable Object errorMessage)202 public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) { 203 if (reference == null) { 204 throw new NullPointerException(String.valueOf(errorMessage)); 205 } 206 return reference; 207 } 208 209 /** 210 * Ensures that an object reference passed as a parameter to the calling 211 * method is not null. 212 * 213 * @param reference an object reference 214 * @param errorMessageTemplate a template for the exception message should the 215 * check fail. The message is formed by replacing each {@code %s} 216 * placeholder in the template with an argument. These are matched by 217 * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 218 * Unmatched arguments will be appended to the formatted message in square 219 * braces. Unmatched placeholders will be left as-is. 220 * @param errorMessageArgs the arguments to be substituted into the message 221 * template. Arguments are converted to strings using 222 * {@link String#valueOf(Object)}. 223 * @return the non-null reference that was validated 224 * @throws NullPointerException if {@code reference} is null 225 */ checkNotNull(T reference, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs)226 public static <T> T checkNotNull(T reference, 227 @Nullable String errorMessageTemplate, 228 @Nullable Object... errorMessageArgs) { 229 if (reference == null) { 230 // If either of these parameters is null, the right thing happens anyway 231 throw new NullPointerException( 232 format(errorMessageTemplate, errorMessageArgs)); 233 } 234 return reference; 235 } 236 237 /* 238 * All recent hotspots (as of 2009) *really* like to have the natural code 239 * 240 * if (guardExpression) { 241 * throw new BadException(messageExpression); 242 * } 243 * 244 * refactored so that messageExpression is moved to a separate 245 * String-returning method. 246 * 247 * if (guardExpression) { 248 * throw new BadException(badMsg(...)); 249 * } 250 * 251 * The alternative natural refactorings into void or Exception-returning 252 * methods are much slower. This is a big deal - we're talking factors of 253 * 2-8 in microbenchmarks, not just 10-20%. (This is a hotspot optimizer 254 * bug, which should be fixed, but that's a separate, big project). 255 * 256 * The coding pattern above is heavily used in java.util, e.g. in ArrayList. 257 * There is a RangeCheckMicroBenchmark in the JDK that was used to test this. 258 * 259 * But the methods in this class want to throw different exceptions, 260 * depending on the args, so it appears that this pattern is not directly 261 * applicable. But we can use the ridiculous, devious trick of throwing an 262 * exception in the middle of the construction of another exception. 263 * Hotspot is fine with that. 264 */ 265 266 /** 267 * Ensures that {@code index} specifies a valid <i>element</i> in an array, 268 * list or string of size {@code size}. An element index may range from zero, 269 * inclusive, to {@code size}, exclusive. 270 * 271 * @param index a user-supplied index identifying an element of an array, list 272 * or string 273 * @param size the size of that array, list or string 274 * @return the value of {@code index} 275 * @throws IndexOutOfBoundsException if {@code index} is negative or is not 276 * less than {@code size} 277 * @throws IllegalArgumentException if {@code size} is negative 278 */ checkElementIndex(int index, int size)279 public static int checkElementIndex(int index, int size) { 280 return checkElementIndex(index, size, "index"); 281 } 282 283 /** 284 * Ensures that {@code index} specifies a valid <i>element</i> in an array, 285 * list or string of size {@code size}. An element index may range from zero, 286 * inclusive, to {@code size}, exclusive. 287 * 288 * @param index a user-supplied index identifying an element of an array, list 289 * or string 290 * @param size the size of that array, list or string 291 * @param desc the text to use to describe this index in an error message 292 * @return the value of {@code index} 293 * @throws IndexOutOfBoundsException if {@code index} is negative or is not 294 * less than {@code size} 295 * @throws IllegalArgumentException if {@code size} is negative 296 */ checkElementIndex( int index, int size, @Nullable String desc)297 public static int checkElementIndex( 298 int index, int size, @Nullable String desc) { 299 // Carefully optimized for execution by hotspot (explanatory comment above) 300 if (index < 0 || index >= size) { 301 throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); 302 } 303 return index; 304 } 305 badElementIndex(int index, int size, String desc)306 private static String badElementIndex(int index, int size, String desc) { 307 if (index < 0) { 308 return format("%s (%s) must not be negative", desc, index); 309 } else if (size < 0) { 310 throw new IllegalArgumentException("negative size: " + size); 311 } else { // index >= size 312 return format("%s (%s) must be less than size (%s)", desc, index, size); 313 } 314 } 315 316 /** 317 * Ensures that {@code index} specifies a valid <i>position</i> in an array, 318 * list or string of size {@code size}. A position index may range from zero 319 * to {@code size}, inclusive. 320 * 321 * @param index a user-supplied index identifying a position in an array, list 322 * or string 323 * @param size the size of that array, list or string 324 * @return the value of {@code index} 325 * @throws IndexOutOfBoundsException if {@code index} is negative or is 326 * greater than {@code size} 327 * @throws IllegalArgumentException if {@code size} is negative 328 */ checkPositionIndex(int index, int size)329 public static int checkPositionIndex(int index, int size) { 330 return checkPositionIndex(index, size, "index"); 331 } 332 333 /** 334 * Ensures that {@code index} specifies a valid <i>position</i> in an array, 335 * list or string of size {@code size}. A position index may range from zero 336 * to {@code size}, inclusive. 337 * 338 * @param index a user-supplied index identifying a position in an array, list 339 * or string 340 * @param size the size of that array, list or string 341 * @param desc the text to use to describe this index in an error message 342 * @return the value of {@code index} 343 * @throws IndexOutOfBoundsException if {@code index} is negative or is 344 * greater than {@code size} 345 * @throws IllegalArgumentException if {@code size} is negative 346 */ checkPositionIndex( int index, int size, @Nullable String desc)347 public static int checkPositionIndex( 348 int index, int size, @Nullable String desc) { 349 // Carefully optimized for execution by hotspot (explanatory comment above) 350 if (index < 0 || index > size) { 351 throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); 352 } 353 return index; 354 } 355 badPositionIndex(int index, int size, String desc)356 private static String badPositionIndex(int index, int size, String desc) { 357 if (index < 0) { 358 return format("%s (%s) must not be negative", desc, index); 359 } else if (size < 0) { 360 throw new IllegalArgumentException("negative size: " + size); 361 } else { // index > size 362 return format("%s (%s) must not be greater than size (%s)", 363 desc, index, size); 364 } 365 } 366 367 /** 368 * Ensures that {@code start} and {@code end} specify a valid <i>positions</i> 369 * in an array, list or string of size {@code size}, and are in order. A 370 * position index may range from zero to {@code size}, inclusive. 371 * 372 * @param start a user-supplied index identifying a starting position in an 373 * array, list or string 374 * @param end a user-supplied index identifying a ending position in an array, 375 * list or string 376 * @param size the size of that array, list or string 377 * @throws IndexOutOfBoundsException if either index is negative or is 378 * greater than {@code size}, or if {@code end} is less than {@code start} 379 * @throws IllegalArgumentException if {@code size} is negative 380 */ checkPositionIndexes(int start, int end, int size)381 public static void checkPositionIndexes(int start, int end, int size) { 382 // Carefully optimized for execution by hotspot (explanatory comment above) 383 if (start < 0 || end < start || end > size) { 384 throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); 385 } 386 } 387 badPositionIndexes(int start, int end, int size)388 private static String badPositionIndexes(int start, int end, int size) { 389 if (start < 0 || start > size) { 390 return badPositionIndex(start, size, "start index"); 391 } 392 if (end < 0 || end > size) { 393 return badPositionIndex(end, size, "end index"); 394 } 395 // end < start 396 return format("end index (%s) must not be less than start index (%s)", 397 end, start); 398 } 399 400 /** 401 * Substitutes each {@code %s} in {@code template} with an argument. These 402 * are matched by position - the first {@code %s} gets {@code args[0]}, etc. 403 * If there are more arguments than placeholders, the unmatched arguments will 404 * be appended to the end of the formatted message in square braces. 405 * 406 * @param template a non-null string containing 0 or more {@code %s} 407 * placeholders. 408 * @param args the arguments to be substituted into the message 409 * template. Arguments are converted to strings using 410 * {@link String#valueOf(Object)}. Arguments can be null. 411 */ format(String template, @Nullable Object... args)412 @VisibleForTesting static String format(String template, 413 @Nullable Object... args) { 414 template = String.valueOf(template); // null -> "null" 415 416 // start substituting the arguments into the '%s' placeholders 417 StringBuilder builder = new StringBuilder( 418 template.length() + 16 * args.length); 419 int templateStart = 0; 420 int i = 0; 421 while (i < args.length) { 422 int placeholderStart = template.indexOf("%s", templateStart); 423 if (placeholderStart == -1) { 424 break; 425 } 426 builder.append(template.substring(templateStart, placeholderStart)); 427 builder.append(args[i++]); 428 templateStart = placeholderStart + 2; 429 } 430 builder.append(template.substring(templateStart)); 431 432 // if we run out of placeholders, append the extra args in square braces 433 if (i < args.length) { 434 builder.append(" ["); 435 builder.append(args[i++]); 436 while (i < args.length) { 437 builder.append(", "); 438 builder.append(args[i++]); 439 } 440 builder.append(']'); 441 } 442 443 return builder.toString(); 444 } 445 } 446