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