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