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
017package com.google.common.base;
018
019import com.google.common.annotations.GwtCompatible;
020import com.google.common.annotations.VisibleForTesting;
021
022import java.util.NoSuchElementException;
023
024import 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
064public 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}