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     * @author Kevin Bourrillion
057     * @since 2 (imported from Google Collections Library)
058     */
059    @GwtCompatible
060    public final class Preconditions {
061      private Preconditions() {}
062    
063      /**
064       * Ensures the truth of an expression involving one or more parameters to the
065       * calling method.
066       *
067       * @param expression a boolean expression
068       * @throws IllegalArgumentException if {@code expression} is false
069       */
070      public static void checkArgument(boolean expression) {
071        if (!expression) {
072          throw new IllegalArgumentException();
073        }
074      }
075    
076      /**
077       * Ensures the truth of an expression involving one or more parameters to the
078       * calling method.
079       *
080       * @param expression a boolean expression
081       * @param errorMessage the exception message to use if the check fails; will
082       *     be converted to a string using {@link String#valueOf(Object)}
083       * @throws IllegalArgumentException if {@code expression} is false
084       */
085      public static void checkArgument(
086          boolean expression, @Nullable Object errorMessage) {
087        if (!expression) {
088          throw new IllegalArgumentException(String.valueOf(errorMessage));
089        }
090      }
091    
092      /**
093       * Ensures the truth of an expression involving one or more parameters to the
094       * calling method.
095       *
096       * @param expression a boolean expression
097       * @param errorMessageTemplate a template for the exception message should the
098       *     check fail. The message is formed by replacing each {@code %s}
099       *     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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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    
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       */
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       */
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    
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       */
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    
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       */
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    }