001    /*
002     * Copyright (C) 2007 The Guava Authors
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package com.google.common.base;
018    
019    import com.google.common.annotations.GwtCompatible;
020    import com.google.common.annotations.VisibleForTesting;
021    
022    import java.util.NoSuchElementException;
023    
024    import javax.annotation.Nullable;
025    
026    /**
027     * Simple static methods to be called at the start of your own methods to verify
028     * correct arguments and state. This allows constructs such as
029     * <pre>
030     *     if (count <= 0) {
031     *       throw new IllegalArgumentException("must be positive: " + count);
032     *     }</pre>
033     *
034     * to be replaced with the more compact
035     * <pre>
036     *     checkArgument(count > 0, "must be positive: %s", count);</pre>
037     *
038     * Note that the sense of the expression is inverted; with {@code Preconditions}
039     * you declare what you expect to be <i>true</i>, just as you do with an
040     * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html">
041     * {@code assert}</a> or a JUnit {@code assertTrue} call.
042     *
043     * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a
044     * placeholder in these messages, not the full range of {@link
045     * String#format(String, Object[])} specifiers.
046     *
047     * <p>Take care not to confuse precondition checking with other similar types
048     * of checks! Precondition exceptions -- including those provided here, but also
049     * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link
050     * UnsupportedOperationException} and others -- are used to signal that the
051     * <i>calling method</i> has made an error. This tells the caller that it should
052     * not have invoked the method when it did, with the arguments it did, or
053     * perhaps ever. Postcondition or other invariant failures should not throw
054     * these types of exceptions.
055     *
056     * <p>See the Guava User Guide on <a href=
057     * "http://code.google.com/p/guava-libraries/wiki/PreconditionsExplained">
058     * using {@code Preconditions}</a>.
059     *
060     * @author Kevin Bourrillion
061     * @since 2.0 (imported from Google Collections Library)
062     */
063    @GwtCompatible
064    public final class Preconditions {
065      private Preconditions() {}
066    
067      /**
068       * Ensures the truth of an expression involving one or more parameters to the
069       * calling method.
070       *
071       * @param expression a boolean expression
072       * @throws IllegalArgumentException if {@code expression} is false
073       */
074      public static void checkArgument(boolean expression) {
075        if (!expression) {
076          throw new IllegalArgumentException();
077        }
078      }
079    
080      /**
081       * Ensures the truth of an expression involving one or more parameters to the
082       * calling method.
083       *
084       * @param expression a boolean expression
085       * @param errorMessage the exception message to use if the check fails; will
086       *     be converted to a string using {@link String#valueOf(Object)}
087       * @throws IllegalArgumentException if {@code expression} is false
088       */
089      public static void checkArgument(
090          boolean expression, @Nullable Object errorMessage) {
091        if (!expression) {
092          throw new IllegalArgumentException(String.valueOf(errorMessage));
093        }
094      }
095    
096      /**
097       * Ensures the truth of an expression involving one or more parameters to the
098       * calling method.
099       *
100       * @param expression a boolean expression
101       * @param errorMessageTemplate a template for the exception message should the
102       *     check fail. The message is formed by replacing each {@code %s}
103       *     placeholder in the template with an argument. These are matched by
104       *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
105       *     Unmatched arguments will be appended to the formatted message in square
106       *     braces. Unmatched placeholders will be left as-is.
107       * @param errorMessageArgs the arguments to be substituted into the message
108       *     template. Arguments are converted to strings using
109       *     {@link String#valueOf(Object)}.
110       * @throws IllegalArgumentException if {@code expression} is false
111       * @throws NullPointerException if the check fails and either {@code
112       *     errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
113       *     this happen)
114       */
115      public static void checkArgument(boolean expression,
116          @Nullable String errorMessageTemplate,
117          @Nullable Object... errorMessageArgs) {
118        if (!expression) {
119          throw new IllegalArgumentException(
120              format(errorMessageTemplate, errorMessageArgs));
121        }
122      }
123    
124      /**
125       * Ensures the truth of an expression involving the state of the calling
126       * instance, but not involving any parameters to the calling method.
127       *
128       * @param expression a boolean expression
129       * @throws IllegalStateException if {@code expression} is false
130       */
131      public static void checkState(boolean expression) {
132        if (!expression) {
133          throw new IllegalStateException();
134        }
135      }
136    
137      /**
138       * Ensures the truth of an expression involving the state of the calling
139       * instance, but not involving any parameters to the calling method.
140       *
141       * @param expression a boolean expression
142       * @param errorMessage the exception message to use if the check fails; will
143       *     be converted to a string using {@link String#valueOf(Object)}
144       * @throws IllegalStateException if {@code expression} is false
145       */
146      public static void checkState(
147          boolean expression, @Nullable Object errorMessage) {
148        if (!expression) {
149          throw new IllegalStateException(String.valueOf(errorMessage));
150        }
151      }
152    
153      /**
154       * Ensures the truth of an expression involving the state of the calling
155       * instance, but not involving any parameters to the calling method.
156       *
157       * @param expression a boolean expression
158       * @param errorMessageTemplate a template for the exception message should the
159       *     check fail. The message is formed by replacing each {@code %s}
160       *     placeholder in the template with an argument. These are matched by
161       *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
162       *     Unmatched arguments will be appended to the formatted message in square
163       *     braces. Unmatched placeholders will be left as-is.
164       * @param errorMessageArgs the arguments to be substituted into the message
165       *     template. Arguments are converted to strings using
166       *     {@link String#valueOf(Object)}.
167       * @throws IllegalStateException if {@code expression} is false
168       * @throws NullPointerException if the check fails and either {@code
169       *     errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
170       *     this happen)
171       */
172      public static void checkState(boolean expression,
173          @Nullable String errorMessageTemplate,
174          @Nullable Object... errorMessageArgs) {
175        if (!expression) {
176          throw new IllegalStateException(
177              format(errorMessageTemplate, errorMessageArgs));
178        }
179      }
180    
181      /**
182       * Ensures that an object reference passed as a parameter to the calling
183       * method is not null.
184       *
185       * @param reference an object reference
186       * @return the non-null reference that was validated
187       * @throws NullPointerException if {@code reference} is null
188       */
189      public static <T> T checkNotNull(T reference) {
190        if (reference == null) {
191          throw new NullPointerException();
192        }
193        return reference;
194      }
195    
196      /**
197       * Ensures that an object reference passed as a parameter to the calling
198       * method is not null.
199       *
200       * @param reference an object reference
201       * @param errorMessage the exception message to use if the check fails; will
202       *     be converted to a string using {@link String#valueOf(Object)}
203       * @return the non-null reference that was validated
204       * @throws NullPointerException if {@code reference} is null
205       */
206      public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
207        if (reference == null) {
208          throw new NullPointerException(String.valueOf(errorMessage));
209        }
210        return reference;
211      }
212    
213      /**
214       * Ensures that an object reference passed as a parameter to the calling
215       * method is not null.
216       *
217       * @param reference an object reference
218       * @param errorMessageTemplate a template for the exception message should the
219       *     check fail. The message is formed by replacing each {@code %s}
220       *     placeholder in the template with an argument. These are matched by
221       *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
222       *     Unmatched arguments will be appended to the formatted message in square
223       *     braces. Unmatched placeholders will be left as-is.
224       * @param errorMessageArgs the arguments to be substituted into the message
225       *     template. Arguments are converted to strings using
226       *     {@link String#valueOf(Object)}.
227       * @return the non-null reference that was validated
228       * @throws NullPointerException if {@code reference} is null
229       */
230      public static <T> T checkNotNull(T reference,
231          @Nullable String errorMessageTemplate,
232          @Nullable Object... errorMessageArgs) {
233        if (reference == null) {
234          // If either of these parameters is null, the right thing happens anyway
235          throw new NullPointerException(
236              format(errorMessageTemplate, errorMessageArgs));
237        }
238        return reference;
239      }
240    
241      /*
242       * All recent hotspots (as of 2009) *really* like to have the natural code
243       *
244       * if (guardExpression) {
245       *    throw new BadException(messageExpression);
246       * }
247       *
248       * refactored so that messageExpression is moved to a separate
249       * String-returning method.
250       *
251       * if (guardExpression) {
252       *    throw new BadException(badMsg(...));
253       * }
254       *
255       * The alternative natural refactorings into void or Exception-returning
256       * methods are much slower.  This is a big deal - we're talking factors of
257       * 2-8 in microbenchmarks, not just 10-20%.  (This is a hotspot optimizer
258       * bug, which should be fixed, but that's a separate, big project).
259       *
260       * The coding pattern above is heavily used in java.util, e.g. in ArrayList.
261       * There is a RangeCheckMicroBenchmark in the JDK that was used to test this.
262       *
263       * But the methods in this class want to throw different exceptions,
264       * depending on the args, so it appears that this pattern is not directly
265       * applicable.  But we can use the ridiculous, devious trick of throwing an
266       * exception in the middle of the construction of another exception.
267       * Hotspot is fine with that.
268       */
269    
270      /**
271       * Ensures that {@code index} specifies a valid <i>element</i> in an array,
272       * list or string of size {@code size}. An element index may range from zero,
273       * inclusive, to {@code size}, exclusive.
274       *
275       * @param index a user-supplied index identifying an element of an array, list
276       *     or string
277       * @param size the size of that array, list or string
278       * @return the value of {@code index}
279       * @throws IndexOutOfBoundsException if {@code index} is negative or is not
280       *     less than {@code size}
281       * @throws IllegalArgumentException if {@code size} is negative
282       */
283      public static int checkElementIndex(int index, int size) {
284        return checkElementIndex(index, size, "index");
285      }
286    
287      /**
288       * Ensures that {@code index} specifies a valid <i>element</i> in an array,
289       * list or string of size {@code size}. An element index may range from zero,
290       * inclusive, to {@code size}, exclusive.
291       *
292       * @param index a user-supplied index identifying an element of an array, list
293       *     or string
294       * @param size the size of that array, list or string
295       * @param desc the text to use to describe this index in an error message
296       * @return the value of {@code index}
297       * @throws IndexOutOfBoundsException if {@code index} is negative or is not
298       *     less than {@code size}
299       * @throws IllegalArgumentException if {@code size} is negative
300       */
301      public static int checkElementIndex(
302          int index, int size, @Nullable String desc) {
303        // Carefully optimized for execution by hotspot (explanatory comment above)
304        if (index < 0 || index >= size) {
305          throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
306        }
307        return index;
308      }
309    
310      private static String badElementIndex(int index, int size, String desc) {
311        if (index < 0) {
312          return format("%s (%s) must not be negative", desc, index);
313        } else if (size < 0) {
314          throw new IllegalArgumentException("negative size: " + size);
315        } else { // index >= size
316          return format("%s (%s) must be less than size (%s)", desc, index, size);
317        }
318      }
319    
320      /**
321       * Ensures that {@code index} specifies a valid <i>position</i> in an array,
322       * list or string of size {@code size}. A position index may range from zero
323       * to {@code size}, inclusive.
324       *
325       * @param index a user-supplied index identifying a position in an array, list
326       *     or string
327       * @param size the size of that array, list or string
328       * @return the value of {@code index}
329       * @throws IndexOutOfBoundsException if {@code index} is negative or is
330       *     greater than {@code size}
331       * @throws IllegalArgumentException if {@code size} is negative
332       */
333      public static int checkPositionIndex(int index, int size) {
334        return checkPositionIndex(index, size, "index");
335      }
336    
337      /**
338       * Ensures that {@code index} specifies a valid <i>position</i> in an array,
339       * list or string of size {@code size}. A position index may range from zero
340       * to {@code size}, inclusive.
341       *
342       * @param index a user-supplied index identifying a position in an array, list
343       *     or string
344       * @param size the size of that array, list or string
345       * @param desc the text to use to describe this index in an error message
346       * @return the value of {@code index}
347       * @throws IndexOutOfBoundsException if {@code index} is negative or is
348       *     greater than {@code size}
349       * @throws IllegalArgumentException if {@code size} is negative
350       */
351      public static int checkPositionIndex(
352          int index, int size, @Nullable String desc) {
353        // Carefully optimized for execution by hotspot (explanatory comment above)
354        if (index < 0 || index > size) {
355          throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
356        }
357        return index;
358      }
359    
360      private static String badPositionIndex(int index, int size, String desc) {
361        if (index < 0) {
362          return format("%s (%s) must not be negative", desc, index);
363        } else if (size < 0) {
364          throw new IllegalArgumentException("negative size: " + size);
365        } else { // index > size
366          return format("%s (%s) must not be greater than size (%s)",
367                        desc, index, size);
368        }
369      }
370    
371      /**
372       * Ensures that {@code start} and {@code end} specify a valid <i>positions</i>
373       * in an array, list or string of size {@code size}, and are in order. A
374       * position index may range from zero to {@code size}, inclusive.
375       *
376       * @param start a user-supplied index identifying a starting position in an
377       *     array, list or string
378       * @param end a user-supplied index identifying a ending position in an array,
379       *     list or string
380       * @param size the size of that array, list or string
381       * @throws IndexOutOfBoundsException if either index is negative or is
382       *     greater than {@code size}, or if {@code end} is less than {@code start}
383       * @throws IllegalArgumentException if {@code size} is negative
384       */
385      public static void checkPositionIndexes(int start, int end, int size) {
386        // Carefully optimized for execution by hotspot (explanatory comment above)
387        if (start < 0 || end < start || end > size) {
388          throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
389        }
390      }
391    
392      private static String badPositionIndexes(int start, int end, int size) {
393        if (start < 0 || start > size) {
394          return badPositionIndex(start, size, "start index");
395        }
396        if (end < 0 || end > size) {
397          return badPositionIndex(end, size, "end index");
398        }
399        // end < start
400        return format("end index (%s) must not be less than start index (%s)",
401                      end, start);
402      }
403    
404      /**
405       * Substitutes each {@code %s} in {@code template} with an argument. These
406       * are matched by position - the first {@code %s} gets {@code args[0]}, etc.
407       * If there are more arguments than placeholders, the unmatched arguments will
408       * be appended to the end of the formatted message in square braces.
409       *
410       * @param template a non-null string containing 0 or more {@code %s}
411       *     placeholders.
412       * @param args the arguments to be substituted into the message
413       *     template. Arguments are converted to strings using
414       *     {@link String#valueOf(Object)}. Arguments can be null.
415       */
416      @VisibleForTesting static String format(String template,
417          @Nullable Object... args) {
418        template = String.valueOf(template); // null -> "null"
419    
420        // start substituting the arguments into the '%s' placeholders
421        StringBuilder builder = new StringBuilder(
422            template.length() + 16 * args.length);
423        int templateStart = 0;
424        int i = 0;
425        while (i < args.length) {
426          int placeholderStart = template.indexOf("%s", templateStart);
427          if (placeholderStart == -1) {
428            break;
429          }
430          builder.append(template.substring(templateStart, placeholderStart));
431          builder.append(args[i++]);
432          templateStart = placeholderStart + 2;
433        }
434        builder.append(template.substring(templateStart));
435    
436        // if we run out of placeholders, append the extra args in square braces
437        if (i < args.length) {
438          builder.append(" [");
439          builder.append(args[i++]);
440          while (i < args.length) {
441            builder.append(", ");
442            builder.append(args[i++]);
443          }
444          builder.append(']');
445        }
446    
447        return builder.toString();
448      }
449    }