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