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