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