1993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira/*
2993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Copyright (C) 2007 Google Inc.
3993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
4993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
5993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * you may not use this file except in compliance with the License.
6993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * You may obtain a copy of the License at
7993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
8993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0
9993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
10993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Unless required by applicable law or agreed to in writing, software
11993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
12993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * See the License for the specific language governing permissions and
14993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * limitations under the License.
15993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */
16993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
171bdbfefe4b144c7b031a1d9242a0fa061a0ae6b5Scott Kennedypackage com.google.android.mail.common.base;
18993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
19993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereiraimport java.util.NoSuchElementException;
20993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
21993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira/**
22993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Simple static methods to be called at the start of your own methods to verify
23993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * correct arguments and state. This allows constructs such as
24993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <pre>
25993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *     if (count <= 0) {
26993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *       throw new IllegalArgumentException("must be positive: " + count);
27993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *     }</pre>
28993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
29993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * to be replaced with the more compact
30993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <pre>
31993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *     checkArgument(count > 0, "must be positive: %s", count);</pre>
32993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
33993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * Note that the sense of the expression is inverted; with {@code Preconditions}
34993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * you declare what you expect to be <i>true</i>, just as you do with an
35993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html">
36993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@code assert}</a> or a JUnit {@code assertTrue} call.
37993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
38993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a
39993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * placeholder in these messages, not the full range of {@link
40993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * String#format(String, Object[])} specifiers.
41993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
42993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <p>Take care not to confuse precondition checking with other similar types
43993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * of checks! Precondition exceptions -- including those provided here, but also
44993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link
45993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * UnsupportedOperationException} and others -- are used to signal that the
46993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * <i>calling method</i> has made an error. This tells the caller that it should
47993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * not have invoked the method when it did, with the arguments it did, or
48993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * perhaps ever. Postcondition or other invariant failures should not throw
49993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * these types of exceptions.
50993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira *
51993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @author Kevin Bourrillion
52993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
53993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira */
54993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereirapublic class Preconditions {
55993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  private Preconditions() {}
56993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
57993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
58993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures the truth of an expression involving one or more parameters to the
59993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * calling method.
60993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
61993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param expression a boolean expression
62993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalArgumentException if {@code expression} is false
63993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
64993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static void checkArgument(boolean expression) {
65993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (!expression) {
66993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IllegalArgumentException();
67993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
68993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
69993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
70993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
71993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures the truth of an expression involving one or more parameters to the
72993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * calling method.
73993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
74993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param expression a boolean expression
75993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessage the exception message to use if the check fails; will
76993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     be converted to a string using {@link String#valueOf(Object)}
77993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalArgumentException if {@code expression} is false
78993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
79993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static void checkArgument(boolean expression, Object errorMessage) {
80993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (!expression) {
81993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IllegalArgumentException(String.valueOf(errorMessage));
82993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
83993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
84993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
85993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
86993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures the truth of an expression involving one or more parameters to the
87993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * calling method.
88993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
89993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param expression a boolean expression
90993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessageTemplate a template for the exception message should the
91993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     check fail. The message is formed by replacing each {@code %s}
92993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     placeholder in the template with an argument. These are matched by
93993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
94993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     Unmatched arguments will be appended to the formatted message in square
95993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     braces. Unmatched placeholders will be left as-is.
96993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessageArgs the arguments to be substituted into the message
97993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     template. Arguments are converted to strings using
98993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     {@link String#valueOf(Object)}.
99993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalArgumentException if {@code expression} is false
100993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws NullPointerException if the check fails and either {@code
101993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
102993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     this happen)
103993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
104993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static void checkArgument(boolean expression,
105993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      String errorMessageTemplate, Object... errorMessageArgs) {
106993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (!expression) {
107993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IllegalArgumentException(
108993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira          format(errorMessageTemplate, errorMessageArgs));
109993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
110993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
111993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
112993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
113993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures the truth of an expression involving the state of the calling
114993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * instance, but not involving any parameters to the calling method.
115993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
116993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param expression a boolean expression
117993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalStateException if {@code expression} is false
118993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
119993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static void checkState(boolean expression) {
120993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (!expression) {
121993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IllegalStateException();
122993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
123993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
124993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
125993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
126993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures the truth of an expression involving the state of the calling
127993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * instance, but not involving any parameters to the calling method.
128993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
129993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param expression a boolean expression
130993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessage the exception message to use if the check fails; will
131993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     be converted to a string using {@link String#valueOf(Object)}
132993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalStateException if {@code expression} is false
133993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
134993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static void checkState(boolean expression, Object errorMessage) {
135993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (!expression) {
136993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IllegalStateException(String.valueOf(errorMessage));
137993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
138993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
139993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
140993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
141993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures the truth of an expression involving the state of the calling
142993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * instance, but not involving any parameters to the calling method.
143993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
144993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param expression a boolean expression
145993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessageTemplate a template for the exception message should the
146993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     check fail. The message is formed by replacing each {@code %s}
147993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     placeholder in the template with an argument. These are matched by
148993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
149993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     Unmatched arguments will be appended to the formatted message in square
150993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     braces. Unmatched placeholders will be left as-is.
151993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessageArgs the arguments to be substituted into the message
152993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     template. Arguments are converted to strings using
153993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     {@link String#valueOf(Object)}.
154993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalStateException if {@code expression} is false
155993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws NullPointerException if the check fails and either {@code
156993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
157993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     this happen)
158993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
159993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static void checkState(boolean expression,
160993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      String errorMessageTemplate, Object... errorMessageArgs) {
161993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (!expression) {
162993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IllegalStateException(
163993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira          format(errorMessageTemplate, errorMessageArgs));
164993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
165993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
166993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
167993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
168993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures that an object reference passed as a parameter to the calling
169993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * method is not null.
170993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
171993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param reference an object reference
172993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the non-null reference that was validated
173993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws NullPointerException if {@code reference} is null
174993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
175993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static <T> T checkNotNull(T reference) {
176993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (reference == null) {
177993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new NullPointerException();
178993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
179993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return reference;
180993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
181993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
182993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
183993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures that an object reference passed as a parameter to the calling
184993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * method is not null.
185993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
186993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param reference an object reference
187993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessage the exception message to use if the check fails; will
188993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     be converted to a string using {@link String#valueOf(Object)}
189993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the non-null reference that was validated
190993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws NullPointerException if {@code reference} is null
191993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
192993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static <T> T checkNotNull(T reference, Object errorMessage) {
193993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (reference == null) {
194993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new NullPointerException(String.valueOf(errorMessage));
195993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
196993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return reference;
197993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
198993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
199993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
200993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures that an object reference passed as a parameter to the calling
201993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * method is not null.
202993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
203993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param reference an object reference
204993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessageTemplate a template for the exception message should the
205993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     check fail. The message is formed by replacing each {@code %s}
206993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     placeholder in the template with an argument. These are matched by
207993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
208993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     Unmatched arguments will be appended to the formatted message in square
209993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     braces. Unmatched placeholders will be left as-is.
210993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param errorMessageArgs the arguments to be substituted into the message
211993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     template. Arguments are converted to strings using
212993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     {@link String#valueOf(Object)}.
213993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the non-null reference that was validated
214993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws NullPointerException if {@code reference} is null
215993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
216993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static <T> T checkNotNull(T reference, String errorMessageTemplate,
217993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      Object... errorMessageArgs) {
218993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (reference == null) {
219993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      // If either of these parameters is null, the right thing happens anyway
220993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new NullPointerException(
221993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira          format(errorMessageTemplate, errorMessageArgs));
222993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
223993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return reference;
224993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
225993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
226993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /*
227993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * All recent hotspots (as of 2009) *really* like to have the natural code
228993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
229993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * if (guardExpression) {
230993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *    throw new BadException(messageExpression);
231993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * }
232993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
233993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * refactored so that messageExpression is moved to a separate
234993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * String-returning method.
235993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
236993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * if (guardExpression) {
237993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *    throw new BadException(badMsg(...));
238993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * }
239993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
240993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * The alternative natural refactorings into void or Exception-returning
241993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * methods are much slower.  This is a big deal - we're talking factors of
242993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * 2-8 in microbenchmarks, not just 10-20%.  (This is a hotspot optimizer
243993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * bug, which should be fixed, but that's a separate, big project).
244993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
245993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * The coding pattern above is heavily used in java.util, e.g. in ArrayList.
246993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * There is a RangeCheckMicroBenchmark in the JDK that was used to test this.
247993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
248993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * But the methods in this class want to throw different exceptions,
249993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * depending on the args, so it appears that this pattern is not directly
250993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * applicable.  But we can use the ridiculous, devious trick of throwing an
251993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * exception in the middle of the construction of another exception.
252993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Hotspot is fine with that.
253993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
254993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
255993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
256993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures that {@code index} specifies a valid <i>element</i> in an array,
257993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * list or string of size {@code size}. An element index may range from zero,
258993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * inclusive, to {@code size}, exclusive.
259993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
260993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param index a user-supplied index identifying an element of an array, list
261993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     or string
262993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param size the size of that array, list or string
263993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the value of {@code index}
264993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IndexOutOfBoundsException if {@code index} is negative or is not
265993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     less than {@code size}
266993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalArgumentException if {@code size} is negative
267993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
268993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static int checkElementIndex(int index, int size) {
269993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return checkElementIndex(index, size, "index");
270993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
271993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
272993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
273993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures that {@code index} specifies a valid <i>element</i> in an array,
274993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * list or string of size {@code size}. An element index may range from zero,
275993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * inclusive, to {@code size}, exclusive.
276993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
277993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param index a user-supplied index identifying an element of an array, list
278993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     or string
279993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param size the size of that array, list or string
280993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param desc the text to use to describe this index in an error message
281993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the value of {@code index}
282993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IndexOutOfBoundsException if {@code index} is negative or is not
283993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     less than {@code size}
284993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalArgumentException if {@code size} is negative
285993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
286993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static int checkElementIndex(int index, int size, String desc) {
287993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // Carefully optimized for execution by hotspot (explanatory comment above)
288993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (index < 0 || index >= size) {
289993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
290993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
291993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return index;
292993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
293993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
294993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  private static String badElementIndex(int index, int size, String desc) {
295993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (index < 0) {
296993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      return format("%s (%s) must not be negative", desc, index);
297993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    } else if (size < 0) {
298993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IllegalArgumentException("negative size: " + size);
299993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    } else { // index >= size
300993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      return format("%s (%s) must be less than size (%s)", desc, index, size);
301993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
302993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
303993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
304993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
305993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures that {@code index} specifies a valid <i>position</i> in an array,
306993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * list or string of size {@code size}. A position index may range from zero
307993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * to {@code size}, inclusive.
308993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
309993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param index a user-supplied index identifying a position in an array, list
310993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     or string
311993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param size the size of that array, list or string
312993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the value of {@code index}
313993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IndexOutOfBoundsException if {@code index} is negative or is
314993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     greater than {@code size}
315993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalArgumentException if {@code size} is negative
316993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
317993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static int checkPositionIndex(int index, int size) {
318993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return checkPositionIndex(index, size, "index");
319993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
320993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
321993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
322993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures that {@code index} specifies a valid <i>position</i> in an array,
323993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * list or string of size {@code size}. A position index may range from zero
324993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * to {@code size}, inclusive.
325993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
326993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param index a user-supplied index identifying a position in an array, list
327993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     or string
328993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param size the size of that array, list or string
329993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param desc the text to use to describe this index in an error message
330993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @return the value of {@code index}
331993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IndexOutOfBoundsException if {@code index} is negative or is
332993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     greater than {@code size}
333993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalArgumentException if {@code size} is negative
334993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
335993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static int checkPositionIndex(int index, int size, String desc) {
336993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // Carefully optimized for execution by hotspot (explanatory comment above)
337993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (index < 0 || index > size) {
338993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
339993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
340993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return index;
341993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
342993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
343993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  private static String badPositionIndex(int index, int size, String desc) {
344993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (index < 0) {
345993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      return format("%s (%s) must not be negative", desc, index);
346993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    } else if (size < 0) {
347993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IllegalArgumentException("negative size: " + size);
348993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    } else { // index > size
349993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      return format("%s (%s) must not be greater than size (%s)",
350993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira                    desc, index, size);
351993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
352993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
353993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
354993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
355993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Ensures that {@code start} and {@code end} specify a valid <i>positions</i>
356993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * in an array, list or string of size {@code size}, and are in order. A
357993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * position index may range from zero to {@code size}, inclusive.
358993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
359993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param start a user-supplied index identifying a starting position in an
360993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     array, list or string
361993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param end a user-supplied index identifying a ending position in an array,
362993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     list or string
363993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param size the size of that array, list or string
364993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IndexOutOfBoundsException if either index is negative or is
365993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     greater than {@code size}, or if {@code end} is less than {@code start}
366993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @throws IllegalArgumentException if {@code size} is negative
367993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
368993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  public static void checkPositionIndexes(int start, int end, int size) {
369993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // Carefully optimized for execution by hotspot (explanatory comment above)
370993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (start < 0 || end < start || end > size) {
371993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
372993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
373993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
374993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
375993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  private static String badPositionIndexes(int start, int end, int size) {
376993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (start < 0 || start > size) {
377993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      return badPositionIndex(start, size, "start index");
378993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
379993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (end < 0 || end > size) {
380993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      return badPositionIndex(end, size, "end index");
381993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
382993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // end < start
383993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return format("end index (%s) must not be less than start index (%s)",
384993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira                  end, start);
385993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
386993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
387993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  /**
388993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * Substitutes each {@code %s} in {@code template} with an argument. These
389993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * are matched by position - the first {@code %s} gets {@code args[0]}, etc.
390993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * If there are more arguments than placeholders, the unmatched arguments will
391993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * be appended to the end of the formatted message in square braces.
392993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *
393993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param template a non-null string containing 0 or more {@code %s}
394993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     placeholders.
395993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   * @param args the arguments to be substituted into the message
396993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     template. Arguments are converted to strings using
397993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   *     {@link String#valueOf(Object)}. Arguments can be null.
398993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira   */
399993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  static String format(String template, Object... args) {
400993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // start substituting the arguments into the '%s' placeholders
401993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    StringBuilder builder = new StringBuilder(
402993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        template.length() + 16 * args.length);
403993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    int templateStart = 0;
404993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    int i = 0;
405993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    while (i < args.length) {
406993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      int placeholderStart = template.indexOf("%s", templateStart);
407993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      if (placeholderStart == -1) {
408993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        break;
409993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
410993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      builder.append(template.substring(templateStart, placeholderStart));
411993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      builder.append(args[i++]);
412993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      templateStart = placeholderStart + 2;
413993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
414993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    builder.append(template.substring(templateStart));
415993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
416993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    // if we run out of placeholders, append the extra args in square braces
417993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    if (i < args.length) {
418993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      builder.append(" [");
419993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      builder.append(args[i++]);
420993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      while (i < args.length) {
421993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        builder.append(", ");
422993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira        builder.append(args[i++]);
423993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      }
424993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira      builder.append("]");
425993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    }
426993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira
427993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira    return builder.toString();
428993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira  }
429993ef2674bf860a84c5c17e51a7a9e13e5d56504Mindy Pereira}
430