Preconditions.java revision d74d1e549168ba521e8009961b76e8718be37aa1
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 String checkStringNotEmpty(final String 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 String checkStringNotEmpty(final String 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 the truth of an expression involving the state of the calling
118     * instance, but not involving any parameters to the calling method.
119     *
120     * @param expression a boolean expression
121     * @param message exception message
122     * @throws IllegalStateException if {@code expression} is false
123     */
124    public static void checkState(final boolean expression, String message) {
125        if (!expression) {
126            throw new IllegalStateException(message);
127        }
128    }
129
130    /**
131     * Ensures the truth of an expression involving the state of the calling
132     * instance, but not involving any parameters to the calling method.
133     *
134     * @param expression a boolean expression
135     * @throws IllegalStateException if {@code expression} is false
136     */
137    public static void checkState(final boolean expression) {
138        checkState(expression, null);
139    }
140
141    /**
142     * Check the requested flags, throwing if any requested flags are outside
143     * the allowed set.
144     */
145    public static void checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
146        if ((requestedFlags & allowedFlags) != requestedFlags) {
147            throw new IllegalArgumentException("Requested flags 0x"
148                    + Integer.toHexString(requestedFlags) + ", but only 0x"
149                    + Integer.toHexString(allowedFlags) + " are allowed");
150        }
151    }
152
153    /**
154     * Ensures that that the argument numeric value is non-negative.
155     *
156     * @param value a numeric int value
157     * @param errorMessage the exception message to use if the check fails
158     * @return the validated numeric value
159     * @throws IllegalArgumentException if {@code value} was negative
160     */
161    public static @IntRange(from = 0) int checkArgumentNonnegative(final int value,
162            final String errorMessage) {
163        if (value < 0) {
164            throw new IllegalArgumentException(errorMessage);
165        }
166
167        return value;
168    }
169
170    /**
171     * Ensures that that the argument numeric value is non-negative.
172     *
173     * @param value a numeric long value
174     * @param errorMessage the exception message to use if the check fails
175     * @return the validated numeric value
176     * @throws IllegalArgumentException if {@code value} was negative
177     */
178    public static long checkArgumentNonnegative(final long value, final String errorMessage) {
179        if (value < 0) {
180            throw new IllegalArgumentException(errorMessage);
181        }
182
183        return value;
184    }
185
186    /**
187     * Ensures that that the argument numeric value is positive.
188     *
189     * @param value a numeric int value
190     * @param errorMessage the exception message to use if the check fails
191     * @return the validated numeric value
192     * @throws IllegalArgumentException if {@code value} was not positive
193     */
194    public static int checkArgumentPositive(final int value, final String errorMessage) {
195        if (value <= 0) {
196            throw new IllegalArgumentException(errorMessage);
197        }
198
199        return value;
200    }
201
202    /**
203     * Ensures that the argument floating point value is a finite number.
204     *
205     * <p>A finite number is defined to be both representable (that is, not NaN) and
206     * not infinite (that is neither positive or negative infinity).</p>
207     *
208     * @param value a floating point value
209     * @param valueName the name of the argument to use if the check fails
210     *
211     * @return the validated floating point value
212     *
213     * @throws IllegalArgumentException if {@code value} was not finite
214     */
215    public static float checkArgumentFinite(final float value, final String valueName) {
216        if (Float.isNaN(value)) {
217            throw new IllegalArgumentException(valueName + " must not be NaN");
218        } else if (Float.isInfinite(value)) {
219            throw new IllegalArgumentException(valueName + " must not be infinite");
220        }
221
222        return value;
223    }
224
225    /**
226     * Ensures that the argument floating point value is within the inclusive range.
227     *
228     * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
229     * will always be out of range.</p>
230     *
231     * @param value a floating point value
232     * @param lower the lower endpoint of the inclusive range
233     * @param upper the upper endpoint of the inclusive range
234     * @param valueName the name of the argument to use if the check fails
235     *
236     * @return the validated floating point value
237     *
238     * @throws IllegalArgumentException if {@code value} was not within the range
239     */
240    public static float checkArgumentInRange(float value, float lower, float upper,
241            String valueName) {
242        if (Float.isNaN(value)) {
243            throw new IllegalArgumentException(valueName + " must not be NaN");
244        } else if (value < lower) {
245            throw new IllegalArgumentException(
246                    String.format(
247                            "%s is out of range of [%f, %f] (too low)", valueName, lower, upper));
248        } else if (value > upper) {
249            throw new IllegalArgumentException(
250                    String.format(
251                            "%s is out of range of [%f, %f] (too high)", valueName, lower, upper));
252        }
253
254        return value;
255    }
256
257    /**
258     * Ensures that the argument int value is within the inclusive range.
259     *
260     * @param value a int value
261     * @param lower the lower endpoint of the inclusive range
262     * @param upper the upper endpoint of the inclusive range
263     * @param valueName the name of the argument to use if the check fails
264     *
265     * @return the validated int value
266     *
267     * @throws IllegalArgumentException if {@code value} was not within the range
268     */
269    public static int checkArgumentInRange(int value, int lower, int upper,
270            String valueName) {
271        if (value < lower) {
272            throw new IllegalArgumentException(
273                    String.format(
274                            "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
275        } else if (value > upper) {
276            throw new IllegalArgumentException(
277                    String.format(
278                            "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
279        }
280
281        return value;
282    }
283
284    /**
285     * Ensures that the argument long value is within the inclusive range.
286     *
287     * @param value a long value
288     * @param lower the lower endpoint of the inclusive range
289     * @param upper the upper endpoint of the inclusive range
290     * @param valueName the name of the argument to use if the check fails
291     *
292     * @return the validated long value
293     *
294     * @throws IllegalArgumentException if {@code value} was not within the range
295     */
296    public static long checkArgumentInRange(long value, long lower, long upper,
297            String valueName) {
298        if (value < lower) {
299            throw new IllegalArgumentException(
300                    String.format(
301                            "%s is out of range of [%d, %d] (too low)", valueName, lower, upper));
302        } else if (value > upper) {
303            throw new IllegalArgumentException(
304                    String.format(
305                            "%s is out of range of [%d, %d] (too high)", valueName, lower, upper));
306        }
307
308        return value;
309    }
310
311    /**
312     * Ensures that the array is not {@code null}, and none of its elements are {@code null}.
313     *
314     * @param value an array of boxed objects
315     * @param valueName the name of the argument to use if the check fails
316     *
317     * @return the validated array
318     *
319     * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
320     */
321    public static <T> T[] checkArrayElementsNotNull(final T[] value, final String valueName) {
322        if (value == null) {
323            throw new NullPointerException(valueName + " must not be null");
324        }
325
326        for (int i = 0; i < value.length; ++i) {
327            if (value[i] == null) {
328                throw new NullPointerException(
329                        String.format("%s[%d] must not be null", valueName, i));
330            }
331        }
332
333        return value;
334    }
335
336    /**
337     * Ensures that the {@link Collection} is not {@code null}, and none of its elements are
338     * {@code null}.
339     *
340     * @param value a {@link Collection} of boxed objects
341     * @param valueName the name of the argument to use if the check fails
342     *
343     * @return the validated {@link Collection}
344     *
345     * @throws NullPointerException if the {@code value} or any of its elements were {@code null}
346     */
347    public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull(
348            final C value, final String valueName) {
349        if (value == null) {
350            throw new NullPointerException(valueName + " must not be null");
351        }
352
353        long ctr = 0;
354        for (T elem : value) {
355            if (elem == null) {
356                throw new NullPointerException(
357                        String.format("%s[%d] must not be null", valueName, ctr));
358            }
359            ++ctr;
360        }
361
362        return value;
363    }
364
365    /**
366     * Ensures that the {@link Collection} is not {@code null}, and contains at least one element.
367     *
368     * @param value a {@link Collection} of boxed elements.
369     * @param valueName the name of the argument to use if the check fails.
370
371     * @return the validated {@link Collection}
372     *
373     * @throws NullPointerException if the {@code value} was {@code null}
374     * @throws IllegalArgumentException if the {@code value} was empty
375     */
376    public static <T> Collection<T> checkCollectionNotEmpty(final Collection<T> value,
377            final String valueName) {
378        if (value == null) {
379            throw new NullPointerException(valueName + " must not be null");
380        }
381        if (value.isEmpty()) {
382            throw new IllegalArgumentException(valueName + " is empty");
383        }
384        return value;
385    }
386
387    /**
388     * Ensures that all elements in the argument floating point array are within the inclusive range
389     *
390     * <p>While this can be used to range check against +/- infinity, note that all NaN numbers
391     * will always be out of range.</p>
392     *
393     * @param value a floating point array of values
394     * @param lower the lower endpoint of the inclusive range
395     * @param upper the upper endpoint of the inclusive range
396     * @param valueName the name of the argument to use if the check fails
397     *
398     * @return the validated floating point value
399     *
400     * @throws IllegalArgumentException if any of the elements in {@code value} were out of range
401     * @throws NullPointerException if the {@code value} was {@code null}
402     */
403    public static float[] checkArrayElementsInRange(float[] value, float lower, float upper,
404            String valueName) {
405        checkNotNull(value, valueName + " must not be null");
406
407        for (int i = 0; i < value.length; ++i) {
408            float v = value[i];
409
410            if (Float.isNaN(v)) {
411                throw new IllegalArgumentException(valueName + "[" + i + "] must not be NaN");
412            } else if (v < lower) {
413                throw new IllegalArgumentException(
414                        String.format("%s[%d] is out of range of [%f, %f] (too low)",
415                                valueName, i, lower, upper));
416            } else if (v > upper) {
417                throw new IllegalArgumentException(
418                        String.format("%s[%d] is out of range of [%f, %f] (too high)",
419                                valueName, i, lower, upper));
420            }
421        }
422
423        return value;
424    }
425}
426