1 /* 2 * Copyright (C) 2011 The Android Open Source Project 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.android.internal.util; 18 19 import android.annotation.IntRange; 20 import android.annotation.NonNull; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.text.TextUtils; 23 24 import java.util.Collection; 25 26 /** 27 * Simple static methods to be called at the start of your own methods to verify 28 * correct arguments and state. 29 */ 30 public class Preconditions { 31 32 @UnsupportedAppUsage checkArgument(boolean expression)33 public static void checkArgument(boolean expression) { 34 if (!expression) { 35 throw new IllegalArgumentException(); 36 } 37 } 38 39 /** 40 * Ensures that an expression checking an argument is true. 41 * 42 * @param expression the expression to check 43 * @param errorMessage the exception message to use if the check fails; will 44 * be converted to a string using {@link String#valueOf(Object)} 45 * @throws IllegalArgumentException if {@code expression} is false 46 */ 47 @UnsupportedAppUsage checkArgument(boolean expression, final Object errorMessage)48 public static void checkArgument(boolean expression, final Object errorMessage) { 49 if (!expression) { 50 throw new IllegalArgumentException(String.valueOf(errorMessage)); 51 } 52 } 53 54 /** 55 * Ensures that an expression checking an argument is true. 56 * 57 * @param expression the expression to check 58 * @param messageTemplate a printf-style message template to use if the check fails; will 59 * be converted to a string using {@link String#format(String, Object...)} 60 * @param messageArgs arguments for {@code messageTemplate} 61 * @throws IllegalArgumentException if {@code expression} is false 62 */ checkArgument(boolean expression, final String messageTemplate, final Object... messageArgs)63 public static void checkArgument(boolean expression, 64 final String messageTemplate, 65 final Object... messageArgs) { 66 if (!expression) { 67 throw new IllegalArgumentException(String.format(messageTemplate, messageArgs)); 68 } 69 } 70 71 /** 72 * Ensures that an string reference passed as a parameter to the calling 73 * method is not empty. 74 * 75 * @param string an string reference 76 * @return the string reference that was validated 77 * @throws IllegalArgumentException if {@code string} is empty 78 */ checkStringNotEmpty(final T string)79 public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) { 80 if (TextUtils.isEmpty(string)) { 81 throw new IllegalArgumentException(); 82 } 83 return string; 84 } 85 86 /** 87 * Ensures that an string reference passed as a parameter to the calling 88 * method is not empty. 89 * 90 * @param string an string reference 91 * @param errorMessage the exception message to use if the check fails; will 92 * be converted to a string using {@link String#valueOf(Object)} 93 * @return the string reference that was validated 94 * @throws IllegalArgumentException if {@code string} is empty 95 */ checkStringNotEmpty(final T string, final Object errorMessage)96 public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string, 97 final Object errorMessage) { 98 if (TextUtils.isEmpty(string)) { 99 throw new IllegalArgumentException(String.valueOf(errorMessage)); 100 } 101 return string; 102 } 103 104 /** 105 * Ensures that an string reference passed as a parameter to the calling method is not empty. 106 * 107 * @param string an string reference 108 * @param messageTemplate a printf-style message template to use if the check fails; will be 109 * converted to a string using {@link String#format(String, Object...)} 110 * @param messageArgs arguments for {@code messageTemplate} 111 * @return the string reference that was validated 112 * @throws IllegalArgumentException if {@code string} is empty 113 */ checkStringNotEmpty( final T string, final String messageTemplate, final Object... messageArgs)114 public static @NonNull <T extends CharSequence> T checkStringNotEmpty( 115 final T string, final String messageTemplate, final Object... messageArgs) { 116 if (TextUtils.isEmpty(string)) { 117 throw new IllegalArgumentException(String.format(messageTemplate, messageArgs)); 118 } 119 return string; 120 } 121 122 /** 123 * Ensures that an object reference passed as a parameter to the calling 124 * method is not null. 125 * 126 * @param reference an object reference 127 * @return the non-null reference that was validated 128 * @throws NullPointerException if {@code reference} is null 129 * @deprecated - use {@link java.util.Objects.requireNonNull} instead. 130 */ 131 @Deprecated 132 @UnsupportedAppUsage checkNotNull(final T reference)133 public static @NonNull <T> T checkNotNull(final T reference) { 134 if (reference == null) { 135 throw new NullPointerException(); 136 } 137 return reference; 138 } 139 140 /** 141 * Ensures that an object reference passed as a parameter to the calling 142 * method is not null. 143 * 144 * @param reference an object reference 145 * @param errorMessage the exception message to use if the check fails; will 146 * be converted to a string using {@link String#valueOf(Object)} 147 * @return the non-null reference that was validated 148 * @throws NullPointerException if {@code reference} is null 149 * @deprecated - use {@link java.util.Objects.requireNonNull} instead. 150 */ 151 @Deprecated 152 @UnsupportedAppUsage checkNotNull(final T reference, final Object errorMessage)153 public static @NonNull <T> T checkNotNull(final T reference, final Object errorMessage) { 154 if (reference == null) { 155 throw new NullPointerException(String.valueOf(errorMessage)); 156 } 157 return reference; 158 } 159 160 /** 161 * Ensures the truth of an expression involving the state of the calling 162 * instance, but not involving any parameters to the calling method. 163 * 164 * @param expression a boolean expression 165 * @param message exception message 166 * @throws IllegalStateException if {@code expression} is false 167 */ 168 @UnsupportedAppUsage checkState(final boolean expression, String message)169 public static void checkState(final boolean expression, String message) { 170 if (!expression) { 171 throw new IllegalStateException(message); 172 } 173 } 174 175 /** 176 * Ensures the truth of an expression involving the state of the calling 177 * instance, but not involving any parameters to the calling method. 178 * 179 * @param expression a boolean expression 180 * @throws IllegalStateException if {@code expression} is false 181 */ 182 @UnsupportedAppUsage checkState(final boolean expression)183 public static void checkState(final boolean expression) { 184 checkState(expression, null); 185 } 186 187 /** 188 * Check the requested flags, throwing if any requested flags are outside 189 * the allowed set. 190 * 191 * @return the validated requested flags. 192 */ checkFlagsArgument(final int requestedFlags, final int allowedFlags)193 public static int checkFlagsArgument(final int requestedFlags, final int allowedFlags) { 194 if ((requestedFlags & allowedFlags) != requestedFlags) { 195 throw new IllegalArgumentException("Requested flags 0x" 196 + Integer.toHexString(requestedFlags) + ", but only 0x" 197 + Integer.toHexString(allowedFlags) + " are allowed"); 198 } 199 200 return requestedFlags; 201 } 202 203 /** 204 * Ensures that that the argument numeric value is non-negative (greater than or equal to 0). 205 * 206 * @param value a numeric int value 207 * @param errorMessage the exception message to use if the check fails 208 * @return the validated numeric value 209 * @throws IllegalArgumentException if {@code value} was negative 210 */ checkArgumentNonnegative(final int value, final String errorMessage)211 public static @IntRange(from = 0) int checkArgumentNonnegative(final int value, 212 final String errorMessage) { 213 if (value < 0) { 214 throw new IllegalArgumentException(errorMessage); 215 } 216 217 return value; 218 } 219 220 /** 221 * Ensures that that the argument numeric value is non-negative (greater than or equal to 0). 222 * 223 * @param value a numeric int value 224 * 225 * @return the validated numeric value 226 * @throws IllegalArgumentException if {@code value} was negative 227 */ checkArgumentNonnegative(final int value)228 public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) { 229 if (value < 0) { 230 throw new IllegalArgumentException(); 231 } 232 233 return value; 234 } 235 236 /** 237 * Ensures that that the argument numeric value is non-negative (greater than or equal to 0). 238 * 239 * @param value a numeric long value 240 * @return the validated numeric value 241 * @throws IllegalArgumentException if {@code value} was negative 242 */ checkArgumentNonnegative(final long value)243 public static long checkArgumentNonnegative(final long value) { 244 if (value < 0) { 245 throw new IllegalArgumentException(); 246 } 247 248 return value; 249 } 250 251 /** 252 * Ensures that that the argument numeric value is non-negative (greater than or equal to 0). 253 * 254 * @param value a numeric long value 255 * @param errorMessage the exception message to use if the check fails 256 * @return the validated numeric value 257 * @throws IllegalArgumentException if {@code value} was negative 258 */ checkArgumentNonnegative(final long value, final String errorMessage)259 public static long checkArgumentNonnegative(final long value, final String errorMessage) { 260 if (value < 0) { 261 throw new IllegalArgumentException(errorMessage); 262 } 263 264 return value; 265 } 266 267 /** 268 * Ensures that that the argument numeric value is positive (greater than 0). 269 * 270 * @param value a numeric int value 271 * @param errorMessage the exception message to use if the check fails 272 * @return the validated numeric value 273 * @throws IllegalArgumentException if {@code value} was not positive 274 */ checkArgumentPositive(final int value, final String errorMessage)275 public static int checkArgumentPositive(final int value, final String errorMessage) { 276 if (value <= 0) { 277 throw new IllegalArgumentException(errorMessage); 278 } 279 280 return value; 281 } 282 283 /** 284 * Ensures that the argument floating point value is non-negative (greater than or equal to 0). 285 * @param value a floating point value 286 * @param errorMessage the exteption message to use if the check fails 287 * @return the validated numeric value 288 * @throws IllegalArgumentException if {@code value} was negative 289 */ checkArgumentNonNegative(final float value, final String errorMessage)290 public static float checkArgumentNonNegative(final float value, final String errorMessage) { 291 if (value < 0) { 292 throw new IllegalArgumentException(errorMessage); 293 } 294 295 return value; 296 } 297 298 /** 299 * Ensures that the argument floating point value is positive (greater than 0). 300 * @param value a floating point value 301 * @param errorMessage the exteption message to use if the check fails 302 * @return the validated numeric value 303 * @throws IllegalArgumentException if {@code value} was not positive 304 */ checkArgumentPositive(final float value, final String errorMessage)305 public static float checkArgumentPositive(final float value, final String errorMessage) { 306 if (value <= 0) { 307 throw new IllegalArgumentException(errorMessage); 308 } 309 310 return value; 311 } 312 313 /** 314 * Ensures that the argument floating point value is a finite number. 315 * 316 * <p>A finite number is defined to be both representable (that is, not NaN) and 317 * not infinite (that is neither positive or negative infinity).</p> 318 * 319 * @param value a floating point value 320 * @param valueName the name of the argument to use if the check fails 321 * 322 * @return the validated floating point value 323 * 324 * @throws IllegalArgumentException if {@code value} was not finite 325 */ checkArgumentFinite(final float value, final String valueName)326 public static float checkArgumentFinite(final float value, final String valueName) { 327 if (Float.isNaN(value)) { 328 throw new IllegalArgumentException(valueName + " must not be NaN"); 329 } else if (Float.isInfinite(value)) { 330 throw new IllegalArgumentException(valueName + " must not be infinite"); 331 } 332 333 return value; 334 } 335 336 /** 337 * Ensures that the argument floating point value is within the inclusive range. 338 * 339 * <p>While this can be used to range check against +/- infinity, note that all NaN numbers 340 * will always be out of range.</p> 341 * 342 * @param value a floating point value 343 * @param lower the lower endpoint of the inclusive range 344 * @param upper the upper endpoint of the inclusive range 345 * @param valueName the name of the argument to use if the check fails 346 * 347 * @return the validated floating point value 348 * 349 * @throws IllegalArgumentException if {@code value} was not within the range 350 */ checkArgumentInRange(float value, float lower, float upper, String valueName)351 public static float checkArgumentInRange(float value, float lower, float upper, 352 String valueName) { 353 if (Float.isNaN(value)) { 354 throw new IllegalArgumentException(valueName + " must not be NaN"); 355 } else if (value < lower) { 356 throw new IllegalArgumentException( 357 String.format( 358 "%s is out of range of [%f, %f] (too low)", valueName, lower, upper)); 359 } else if (value > upper) { 360 throw new IllegalArgumentException( 361 String.format( 362 "%s is out of range of [%f, %f] (too high)", valueName, lower, upper)); 363 } 364 365 return value; 366 } 367 368 /** 369 * Ensures that the argument int value is within the inclusive range. 370 * 371 * @param value a int value 372 * @param lower the lower endpoint of the inclusive range 373 * @param upper the upper endpoint of the inclusive range 374 * @param valueName the name of the argument to use if the check fails 375 * 376 * @return the validated int value 377 * 378 * @throws IllegalArgumentException if {@code value} was not within the range 379 */ 380 @UnsupportedAppUsage checkArgumentInRange(int value, int lower, int upper, String valueName)381 public static int checkArgumentInRange(int value, int lower, int upper, 382 String valueName) { 383 if (value < lower) { 384 throw new IllegalArgumentException( 385 String.format( 386 "%s is out of range of [%d, %d] (too low)", valueName, lower, upper)); 387 } else if (value > upper) { 388 throw new IllegalArgumentException( 389 String.format( 390 "%s is out of range of [%d, %d] (too high)", valueName, lower, upper)); 391 } 392 393 return value; 394 } 395 396 /** 397 * Ensures that the argument long value is within the inclusive range. 398 * 399 * @param value a long value 400 * @param lower the lower endpoint of the inclusive range 401 * @param upper the upper endpoint of the inclusive range 402 * @param valueName the name of the argument to use if the check fails 403 * 404 * @return the validated long value 405 * 406 * @throws IllegalArgumentException if {@code value} was not within the range 407 */ checkArgumentInRange(long value, long lower, long upper, String valueName)408 public static long checkArgumentInRange(long value, long lower, long upper, 409 String valueName) { 410 if (value < lower) { 411 throw new IllegalArgumentException( 412 String.format( 413 "%s is out of range of [%d, %d] (too low)", valueName, lower, upper)); 414 } else if (value > upper) { 415 throw new IllegalArgumentException( 416 String.format( 417 "%s is out of range of [%d, %d] (too high)", valueName, lower, upper)); 418 } 419 420 return value; 421 } 422 423 /** 424 * Ensures that the array is not {@code null}, and none of its elements are {@code null}. 425 * 426 * @param value an array of boxed objects 427 * @param valueName the name of the argument to use if the check fails 428 * 429 * @return the validated array 430 * 431 * @throws NullPointerException if the {@code value} or any of its elements were {@code null} 432 */ checkArrayElementsNotNull(final T[] value, final String valueName)433 public static <T> T[] checkArrayElementsNotNull(final T[] value, final String valueName) { 434 if (value == null) { 435 throw new NullPointerException(valueName + " must not be null"); 436 } 437 438 for (int i = 0; i < value.length; ++i) { 439 if (value[i] == null) { 440 throw new NullPointerException( 441 String.format("%s[%d] must not be null", valueName, i)); 442 } 443 } 444 445 return value; 446 } 447 448 /** 449 * Ensures that the {@link Collection} is not {@code null}, and none of its elements are 450 * {@code null}. 451 * 452 * @param value a {@link Collection} of boxed objects 453 * @param valueName the name of the argument to use if the check fails 454 * 455 * @return the validated {@link Collection} 456 * 457 * @throws NullPointerException if the {@code value} or any of its elements were {@code null} 458 */ checkCollectionElementsNotNull( final C value, final String valueName)459 public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull( 460 final C value, final String valueName) { 461 if (value == null) { 462 throw new NullPointerException(valueName + " must not be null"); 463 } 464 465 long ctr = 0; 466 for (T elem : value) { 467 if (elem == null) { 468 throw new NullPointerException( 469 String.format("%s[%d] must not be null", valueName, ctr)); 470 } 471 ++ctr; 472 } 473 474 return value; 475 } 476 477 /** 478 * Ensures that the {@link Collection} is not {@code null}, and contains at least one element. 479 * 480 * @param value a {@link Collection} of boxed elements. 481 * @param valueName the name of the argument to use if the check fails. 482 483 * @return the validated {@link Collection} 484 * 485 * @throws NullPointerException if the {@code value} was {@code null} 486 * @throws IllegalArgumentException if the {@code value} was empty 487 */ checkCollectionNotEmpty(final Collection<T> value, final String valueName)488 public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value, 489 final String valueName) { 490 if (value == null) { 491 throw new NullPointerException(valueName + " must not be null"); 492 } 493 if (value.isEmpty()) { 494 throw new IllegalArgumentException(valueName + " is empty"); 495 } 496 return value; 497 } 498 499 /** 500 * Ensures that all elements in the argument floating point array are within the inclusive range 501 * 502 * <p>While this can be used to range check against +/- infinity, note that all NaN numbers 503 * will always be out of range.</p> 504 * 505 * @param value a floating point array of values 506 * @param lower the lower endpoint of the inclusive range 507 * @param upper the upper endpoint of the inclusive range 508 * @param valueName the name of the argument to use if the check fails 509 * 510 * @return the validated floating point value 511 * 512 * @throws IllegalArgumentException if any of the elements in {@code value} were out of range 513 * @throws NullPointerException if the {@code value} was {@code null} 514 */ checkArrayElementsInRange(float[] value, float lower, float upper, String valueName)515 public static float[] checkArrayElementsInRange(float[] value, float lower, float upper, 516 String valueName) { 517 checkNotNull(value, valueName + " must not be null"); 518 519 for (int i = 0; i < value.length; ++i) { 520 float v = value[i]; 521 522 if (Float.isNaN(v)) { 523 throw new IllegalArgumentException(valueName + "[" + i + "] must not be NaN"); 524 } else if (v < lower) { 525 throw new IllegalArgumentException( 526 String.format("%s[%d] is out of range of [%f, %f] (too low)", 527 valueName, i, lower, upper)); 528 } else if (v > upper) { 529 throw new IllegalArgumentException( 530 String.format("%s[%d] is out of range of [%f, %f] (too high)", 531 valueName, i, lower, upper)); 532 } 533 } 534 535 return value; 536 } 537 538 /** 539 * Ensures that all elements in the argument integer array are within the inclusive range 540 * 541 * @param value an integer array of values 542 * @param lower the lower endpoint of the inclusive range 543 * @param upper the upper endpoint of the inclusive range 544 * @param valueName the name of the argument to use if the check fails 545 * 546 * @return the validated integer array 547 * 548 * @throws IllegalArgumentException if any of the elements in {@code value} were out of range 549 * @throws NullPointerException if the {@code value} was {@code null} 550 */ checkArrayElementsInRange(int[] value, int lower, int upper, String valueName)551 public static int[] checkArrayElementsInRange(int[] value, int lower, int upper, 552 String valueName) { 553 checkNotNull(value, valueName + " must not be null"); 554 555 for (int i = 0; i < value.length; ++i) { 556 int v = value[i]; 557 558 if (v < lower) { 559 throw new IllegalArgumentException( 560 String.format("%s[%d] is out of range of [%d, %d] (too low)", 561 valueName, i, lower, upper)); 562 } else if (v > upper) { 563 throw new IllegalArgumentException( 564 String.format("%s[%d] is out of range of [%d, %d] (too high)", 565 valueName, i, lower, upper)); 566 } 567 } 568 569 return value; 570 } 571 } 572