• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
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.google.common.base;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.annotations.VisibleForTesting;
21 
22 import java.util.NoSuchElementException;
23 
24 import javax.annotation.Nullable;
25 
26 /**
27  * Simple static methods to be called at the start of your own methods to verify
28  * correct arguments and state. This allows constructs such as
29  * <pre>
30  *     if (count <= 0) {
31  *       throw new IllegalArgumentException("must be positive: " + count);
32  *     }</pre>
33  *
34  * to be replaced with the more compact
35  * <pre>
36  *     checkArgument(count > 0, "must be positive: %s", count);</pre>
37  *
38  * Note that the sense of the expression is inverted; with {@code Preconditions}
39  * you declare what you expect to be <i>true</i>, just as you do with an
40  * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html">
41  * {@code assert}</a> or a JUnit {@code assertTrue} call.
42  *
43  * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a
44  * placeholder in these messages, not the full range of {@link
45  * String#format(String, Object[])} specifiers.
46  *
47  * <p>Take care not to confuse precondition checking with other similar types
48  * of checks! Precondition exceptions -- including those provided here, but also
49  * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link
50  * UnsupportedOperationException} and others -- are used to signal that the
51  * <i>calling method</i> has made an error. This tells the caller that it should
52  * not have invoked the method when it did, with the arguments it did, or
53  * perhaps ever. Postcondition or other invariant failures should not throw
54  * these types of exceptions.
55  *
56  * @author Kevin Bourrillion
57  * @since 2.0 (imported from Google Collections Library)
58  */
59 @GwtCompatible
60 public final class Preconditions {
Preconditions()61   private Preconditions() {}
62 
63   /**
64    * Ensures the truth of an expression involving one or more parameters to the
65    * calling method.
66    *
67    * @param expression a boolean expression
68    * @throws IllegalArgumentException if {@code expression} is false
69    */
checkArgument(boolean expression)70   public static void checkArgument(boolean expression) {
71     if (!expression) {
72       throw new IllegalArgumentException();
73     }
74   }
75 
76   /**
77    * Ensures the truth of an expression involving one or more parameters to the
78    * calling method.
79    *
80    * @param expression a boolean expression
81    * @param errorMessage the exception message to use if the check fails; will
82    *     be converted to a string using {@link String#valueOf(Object)}
83    * @throws IllegalArgumentException if {@code expression} is false
84    */
checkArgument( boolean expression, @Nullable Object errorMessage)85   public static void checkArgument(
86       boolean expression, @Nullable Object errorMessage) {
87     if (!expression) {
88       throw new IllegalArgumentException(String.valueOf(errorMessage));
89     }
90   }
91 
92   /**
93    * Ensures the truth of an expression involving one or more parameters to the
94    * calling method.
95    *
96    * @param expression a boolean expression
97    * @param errorMessageTemplate a template for the exception message should the
98    *     check fail. The message is formed by replacing each {@code %s}
99    *     placeholder in the template with an argument. These are matched by
100    *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
101    *     Unmatched arguments will be appended to the formatted message in square
102    *     braces. Unmatched placeholders will be left as-is.
103    * @param errorMessageArgs the arguments to be substituted into the message
104    *     template. Arguments are converted to strings using
105    *     {@link String#valueOf(Object)}.
106    * @throws IllegalArgumentException if {@code expression} is false
107    * @throws NullPointerException if the check fails and either {@code
108    *     errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
109    *     this happen)
110    */
checkArgument(boolean expression, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs)111   public static void checkArgument(boolean expression,
112       @Nullable String errorMessageTemplate,
113       @Nullable Object... errorMessageArgs) {
114     if (!expression) {
115       throw new IllegalArgumentException(
116           format(errorMessageTemplate, errorMessageArgs));
117     }
118   }
119 
120   /**
121    * Ensures the truth of an expression involving the state of the calling
122    * instance, but not involving any parameters to the calling method.
123    *
124    * @param expression a boolean expression
125    * @throws IllegalStateException if {@code expression} is false
126    */
checkState(boolean expression)127   public static void checkState(boolean expression) {
128     if (!expression) {
129       throw new IllegalStateException();
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    * @param errorMessage the exception message to use if the check fails; will
139    *     be converted to a string using {@link String#valueOf(Object)}
140    * @throws IllegalStateException if {@code expression} is false
141    */
checkState( boolean expression, @Nullable Object errorMessage)142   public static void checkState(
143       boolean expression, @Nullable Object errorMessage) {
144     if (!expression) {
145       throw new IllegalStateException(String.valueOf(errorMessage));
146     }
147   }
148 
149   /**
150    * Ensures the truth of an expression involving the state of the calling
151    * instance, but not involving any parameters to the calling method.
152    *
153    * @param expression a boolean expression
154    * @param errorMessageTemplate a template for the exception message should the
155    *     check fail. The message is formed by replacing each {@code %s}
156    *     placeholder in the template with an argument. These are matched by
157    *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
158    *     Unmatched arguments will be appended to the formatted message in square
159    *     braces. Unmatched placeholders will be left as-is.
160    * @param errorMessageArgs the arguments to be substituted into the message
161    *     template. Arguments are converted to strings using
162    *     {@link String#valueOf(Object)}.
163    * @throws IllegalStateException if {@code expression} is false
164    * @throws NullPointerException if the check fails and either {@code
165    *     errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
166    *     this happen)
167    */
checkState(boolean expression, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs)168   public static void checkState(boolean expression,
169       @Nullable String errorMessageTemplate,
170       @Nullable Object... errorMessageArgs) {
171     if (!expression) {
172       throw new IllegalStateException(
173           format(errorMessageTemplate, errorMessageArgs));
174     }
175   }
176 
177   /**
178    * Ensures that an object reference passed as a parameter to the calling
179    * method is not null.
180    *
181    * @param reference an object reference
182    * @return the non-null reference that was validated
183    * @throws NullPointerException if {@code reference} is null
184    */
checkNotNull(T reference)185   public static <T> T checkNotNull(T reference) {
186     if (reference == null) {
187       throw new NullPointerException();
188     }
189     return reference;
190   }
191 
192   /**
193    * Ensures that an object reference passed as a parameter to the calling
194    * method is not null.
195    *
196    * @param reference an object reference
197    * @param errorMessage the exception message to use if the check fails; will
198    *     be converted to a string using {@link String#valueOf(Object)}
199    * @return the non-null reference that was validated
200    * @throws NullPointerException if {@code reference} is null
201    */
checkNotNull(T reference, @Nullable Object errorMessage)202   public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
203     if (reference == null) {
204       throw new NullPointerException(String.valueOf(errorMessage));
205     }
206     return reference;
207   }
208 
209   /**
210    * Ensures that an object reference passed as a parameter to the calling
211    * method is not null.
212    *
213    * @param reference an object reference
214    * @param errorMessageTemplate a template for the exception message should the
215    *     check fail. The message is formed by replacing each {@code %s}
216    *     placeholder in the template with an argument. These are matched by
217    *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
218    *     Unmatched arguments will be appended to the formatted message in square
219    *     braces. Unmatched placeholders will be left as-is.
220    * @param errorMessageArgs the arguments to be substituted into the message
221    *     template. Arguments are converted to strings using
222    *     {@link String#valueOf(Object)}.
223    * @return the non-null reference that was validated
224    * @throws NullPointerException if {@code reference} is null
225    */
checkNotNull(T reference, @Nullable String errorMessageTemplate, @Nullable Object... errorMessageArgs)226   public static <T> T checkNotNull(T reference,
227       @Nullable String errorMessageTemplate,
228       @Nullable Object... errorMessageArgs) {
229     if (reference == null) {
230       // If either of these parameters is null, the right thing happens anyway
231       throw new NullPointerException(
232           format(errorMessageTemplate, errorMessageArgs));
233     }
234     return reference;
235   }
236 
237   /*
238    * All recent hotspots (as of 2009) *really* like to have the natural code
239    *
240    * if (guardExpression) {
241    *    throw new BadException(messageExpression);
242    * }
243    *
244    * refactored so that messageExpression is moved to a separate
245    * String-returning method.
246    *
247    * if (guardExpression) {
248    *    throw new BadException(badMsg(...));
249    * }
250    *
251    * The alternative natural refactorings into void or Exception-returning
252    * methods are much slower.  This is a big deal - we're talking factors of
253    * 2-8 in microbenchmarks, not just 10-20%.  (This is a hotspot optimizer
254    * bug, which should be fixed, but that's a separate, big project).
255    *
256    * The coding pattern above is heavily used in java.util, e.g. in ArrayList.
257    * There is a RangeCheckMicroBenchmark in the JDK that was used to test this.
258    *
259    * But the methods in this class want to throw different exceptions,
260    * depending on the args, so it appears that this pattern is not directly
261    * applicable.  But we can use the ridiculous, devious trick of throwing an
262    * exception in the middle of the construction of another exception.
263    * Hotspot is fine with that.
264    */
265 
266   /**
267    * Ensures that {@code index} specifies a valid <i>element</i> in an array,
268    * list or string of size {@code size}. An element index may range from zero,
269    * inclusive, to {@code size}, exclusive.
270    *
271    * @param index a user-supplied index identifying an element of an array, list
272    *     or string
273    * @param size the size of that array, list or string
274    * @return the value of {@code index}
275    * @throws IndexOutOfBoundsException if {@code index} is negative or is not
276    *     less than {@code size}
277    * @throws IllegalArgumentException if {@code size} is negative
278    */
checkElementIndex(int index, int size)279   public static int checkElementIndex(int index, int size) {
280     return checkElementIndex(index, size, "index");
281   }
282 
283   /**
284    * Ensures that {@code index} specifies a valid <i>element</i> in an array,
285    * list or string of size {@code size}. An element index may range from zero,
286    * inclusive, to {@code size}, exclusive.
287    *
288    * @param index a user-supplied index identifying an element of an array, list
289    *     or string
290    * @param size the size of that array, list or string
291    * @param desc the text to use to describe this index in an error message
292    * @return the value of {@code index}
293    * @throws IndexOutOfBoundsException if {@code index} is negative or is not
294    *     less than {@code size}
295    * @throws IllegalArgumentException if {@code size} is negative
296    */
checkElementIndex( int index, int size, @Nullable String desc)297   public static int checkElementIndex(
298       int index, int size, @Nullable String desc) {
299     // Carefully optimized for execution by hotspot (explanatory comment above)
300     if (index < 0 || index >= size) {
301       throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
302     }
303     return index;
304   }
305 
badElementIndex(int index, int size, String desc)306   private static String badElementIndex(int index, int size, String desc) {
307     if (index < 0) {
308       return format("%s (%s) must not be negative", desc, index);
309     } else if (size < 0) {
310       throw new IllegalArgumentException("negative size: " + size);
311     } else { // index >= size
312       return format("%s (%s) must be less than size (%s)", desc, index, size);
313     }
314   }
315 
316   /**
317    * Ensures that {@code index} specifies a valid <i>position</i> in an array,
318    * list or string of size {@code size}. A position index may range from zero
319    * to {@code size}, inclusive.
320    *
321    * @param index a user-supplied index identifying a position in an array, list
322    *     or string
323    * @param size the size of that array, list or string
324    * @return the value of {@code index}
325    * @throws IndexOutOfBoundsException if {@code index} is negative or is
326    *     greater than {@code size}
327    * @throws IllegalArgumentException if {@code size} is negative
328    */
checkPositionIndex(int index, int size)329   public static int checkPositionIndex(int index, int size) {
330     return checkPositionIndex(index, size, "index");
331   }
332 
333   /**
334    * Ensures that {@code index} specifies a valid <i>position</i> in an array,
335    * list or string of size {@code size}. A position index may range from zero
336    * to {@code size}, inclusive.
337    *
338    * @param index a user-supplied index identifying a position in an array, list
339    *     or string
340    * @param size the size of that array, list or string
341    * @param desc the text to use to describe this index in an error message
342    * @return the value of {@code index}
343    * @throws IndexOutOfBoundsException if {@code index} is negative or is
344    *     greater than {@code size}
345    * @throws IllegalArgumentException if {@code size} is negative
346    */
checkPositionIndex( int index, int size, @Nullable String desc)347   public static int checkPositionIndex(
348       int index, int size, @Nullable String desc) {
349     // Carefully optimized for execution by hotspot (explanatory comment above)
350     if (index < 0 || index > size) {
351       throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
352     }
353     return index;
354   }
355 
badPositionIndex(int index, int size, String desc)356   private static String badPositionIndex(int index, int size, String desc) {
357     if (index < 0) {
358       return format("%s (%s) must not be negative", desc, index);
359     } else if (size < 0) {
360       throw new IllegalArgumentException("negative size: " + size);
361     } else { // index > size
362       return format("%s (%s) must not be greater than size (%s)",
363                     desc, index, size);
364     }
365   }
366 
367   /**
368    * Ensures that {@code start} and {@code end} specify a valid <i>positions</i>
369    * in an array, list or string of size {@code size}, and are in order. A
370    * position index may range from zero to {@code size}, inclusive.
371    *
372    * @param start a user-supplied index identifying a starting position in an
373    *     array, list or string
374    * @param end a user-supplied index identifying a ending position in an array,
375    *     list or string
376    * @param size the size of that array, list or string
377    * @throws IndexOutOfBoundsException if either index is negative or is
378    *     greater than {@code size}, or if {@code end} is less than {@code start}
379    * @throws IllegalArgumentException if {@code size} is negative
380    */
checkPositionIndexes(int start, int end, int size)381   public static void checkPositionIndexes(int start, int end, int size) {
382     // Carefully optimized for execution by hotspot (explanatory comment above)
383     if (start < 0 || end < start || end > size) {
384       throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
385     }
386   }
387 
badPositionIndexes(int start, int end, int size)388   private static String badPositionIndexes(int start, int end, int size) {
389     if (start < 0 || start > size) {
390       return badPositionIndex(start, size, "start index");
391     }
392     if (end < 0 || end > size) {
393       return badPositionIndex(end, size, "end index");
394     }
395     // end < start
396     return format("end index (%s) must not be less than start index (%s)",
397                   end, start);
398   }
399 
400   /**
401    * Substitutes each {@code %s} in {@code template} with an argument. These
402    * are matched by position - the first {@code %s} gets {@code args[0]}, etc.
403    * If there are more arguments than placeholders, the unmatched arguments will
404    * be appended to the end of the formatted message in square braces.
405    *
406    * @param template a non-null string containing 0 or more {@code %s}
407    *     placeholders.
408    * @param args the arguments to be substituted into the message
409    *     template. Arguments are converted to strings using
410    *     {@link String#valueOf(Object)}. Arguments can be null.
411    */
format(String template, @Nullable Object... args)412   @VisibleForTesting static String format(String template,
413       @Nullable Object... args) {
414     template = String.valueOf(template); // null -> "null"
415 
416     // start substituting the arguments into the '%s' placeholders
417     StringBuilder builder = new StringBuilder(
418         template.length() + 16 * args.length);
419     int templateStart = 0;
420     int i = 0;
421     while (i < args.length) {
422       int placeholderStart = template.indexOf("%s", templateStart);
423       if (placeholderStart == -1) {
424         break;
425       }
426       builder.append(template.substring(templateStart, placeholderStart));
427       builder.append(args[i++]);
428       templateStart = placeholderStart + 2;
429     }
430     builder.append(template.substring(templateStart));
431 
432     // if we run out of placeholders, append the extra args in square braces
433     if (i < args.length) {
434       builder.append(" [");
435       builder.append(args[i++]);
436       while (i < args.length) {
437         builder.append(", ");
438         builder.append(args[i++]);
439       }
440       builder.append(']');
441     }
442 
443     return builder.toString();
444   }
445 }
446