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