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