18b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira/* 28b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Copyright (C) 2007 Google Inc. 38b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 48b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 58b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * you may not use this file except in compliance with the License. 68b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * You may obtain a copy of the License at 78b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 88b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 98b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 108b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Unless required by applicable law or agreed to in writing, software 118b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 128b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * See the License for the specific language governing permissions and 148b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * limitations under the License. 158b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 168b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.lib.base; 188b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 198b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereiraimport java.util.NoSuchElementException; 208b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 218b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira/** 228b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Simple static methods to be called at the start of your own methods to verify 238b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * correct arguments and state. This allows constructs such as 248b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * <pre> 258b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * if (count <= 0) { 268b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * throw new IllegalArgumentException("must be positive: " + count); 278b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * }</pre> 288b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 298b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * to be replaced with the more compact 308b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * <pre> 318b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * checkArgument(count > 0, "must be positive: %s", count);</pre> 328b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 338b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Note that the sense of the expression is inverted; with {@code Preconditions} 348b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * you declare what you expect to be <i>true</i>, just as you do with an 358b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html"> 368b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * {@code assert}</a> or a JUnit {@code assertTrue} call. 378b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 388b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a 398b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * placeholder in these messages, not the full range of {@link 408b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * String#format(String, Object[])} specifiers. 418b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 428b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * <p>Take care not to confuse precondition checking with other similar types 438b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * of checks! Precondition exceptions -- including those provided here, but also 448b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link 458b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * UnsupportedOperationException} and others -- are used to signal that the 468b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * <i>calling method</i> has made an error. This tells the caller that it should 478b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * not have invoked the method when it did, with the arguments it did, or 488b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * perhaps ever. Postcondition or other invariant failures should not throw 498b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * these types of exceptions. 508b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 518b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @author Kevin Bourrillion 528b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library) 538b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 548b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereirapublic class Preconditions { 558b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira private Preconditions() {} 568b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 578b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 588b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures the truth of an expression involving one or more parameters to the 598b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * calling method. 608b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 618b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param expression a boolean expression 628b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalArgumentException if {@code expression} is false 638b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 648b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static void checkArgument(boolean expression) { 658b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (!expression) { 668b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IllegalArgumentException(); 678b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 688b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 698b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 708b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 718b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures the truth of an expression involving one or more parameters to the 728b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * calling method. 738b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 748b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param expression a boolean expression 758b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessage the exception message to use if the check fails; will 768b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * be converted to a string using {@link String#valueOf(Object)} 778b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalArgumentException if {@code expression} is false 788b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 798b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static void checkArgument(boolean expression, Object errorMessage) { 808b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (!expression) { 818b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IllegalArgumentException(String.valueOf(errorMessage)); 828b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 838b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 848b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 858b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 868b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures the truth of an expression involving one or more parameters to the 878b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * calling method. 888b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 898b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param expression a boolean expression 908b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessageTemplate a template for the exception message should the 918b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * check fail. The message is formed by replacing each {@code %s} 928b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * placeholder in the template with an argument. These are matched by 938b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 948b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Unmatched arguments will be appended to the formatted message in square 958b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * braces. Unmatched placeholders will be left as-is. 968b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessageArgs the arguments to be substituted into the message 978b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * template. Arguments are converted to strings using 988b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * {@link String#valueOf(Object)}. 998b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalArgumentException if {@code expression} is false 1008b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws NullPointerException if the check fails and either {@code 1018b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let 1028b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * this happen) 1038b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 1048b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static void checkArgument(boolean expression, 1058b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira String errorMessageTemplate, Object... errorMessageArgs) { 1068b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (!expression) { 1078b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IllegalArgumentException( 1088b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira format(errorMessageTemplate, errorMessageArgs)); 1098b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1108b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1118b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 1128b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 1138b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures the truth of an expression involving the state of the calling 1148b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * instance, but not involving any parameters to the calling method. 1158b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 1168b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param expression a boolean expression 1178b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalStateException if {@code expression} is false 1188b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 1198b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static void checkState(boolean expression) { 1208b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (!expression) { 1218b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IllegalStateException(); 1228b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1238b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1248b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 1258b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 1268b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures the truth of an expression involving the state of the calling 1278b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * instance, but not involving any parameters to the calling method. 1288b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 1298b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param expression a boolean expression 1308b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessage the exception message to use if the check fails; will 1318b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * be converted to a string using {@link String#valueOf(Object)} 1328b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalStateException if {@code expression} is false 1338b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 1348b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static void checkState(boolean expression, Object errorMessage) { 1358b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (!expression) { 1368b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IllegalStateException(String.valueOf(errorMessage)); 1378b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1388b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1398b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 1408b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 1418b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures the truth of an expression involving the state of the calling 1428b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * instance, but not involving any parameters to the calling method. 1438b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 1448b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param expression a boolean expression 1458b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessageTemplate a template for the exception message should the 1468b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * check fail. The message is formed by replacing each {@code %s} 1478b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * placeholder in the template with an argument. These are matched by 1488b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 1498b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Unmatched arguments will be appended to the formatted message in square 1508b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * braces. Unmatched placeholders will be left as-is. 1518b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessageArgs the arguments to be substituted into the message 1528b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * template. Arguments are converted to strings using 1538b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * {@link String#valueOf(Object)}. 1548b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalStateException if {@code expression} is false 1558b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws NullPointerException if the check fails and either {@code 1568b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let 1578b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * this happen) 1588b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 1598b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static void checkState(boolean expression, 1608b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira String errorMessageTemplate, Object... errorMessageArgs) { 1618b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (!expression) { 1628b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IllegalStateException( 1638b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira format(errorMessageTemplate, errorMessageArgs)); 1648b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1658b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1668b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 1678b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 1688b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures that an object reference passed as a parameter to the calling 1698b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * method is not null. 1708b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 1718b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param reference an object reference 1728b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @return the non-null reference that was validated 1738b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws NullPointerException if {@code reference} is null 1748b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 1758b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static <T> T checkNotNull(T reference) { 1768b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (reference == null) { 1778b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new NullPointerException(); 1788b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1798b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return reference; 1808b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1818b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 1828b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 1838b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures that an object reference passed as a parameter to the calling 1848b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * method is not null. 1858b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 1868b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param reference an object reference 1878b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessage the exception message to use if the check fails; will 1888b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * be converted to a string using {@link String#valueOf(Object)} 1898b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @return the non-null reference that was validated 1908b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws NullPointerException if {@code reference} is null 1918b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 1928b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static <T> T checkNotNull(T reference, Object errorMessage) { 1938b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (reference == null) { 1948b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new NullPointerException(String.valueOf(errorMessage)); 1958b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1968b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return reference; 1978b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 1988b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 1998b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 2008b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures that an object reference passed as a parameter to the calling 2018b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * method is not null. 2028b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2038b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param reference an object reference 2048b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessageTemplate a template for the exception message should the 2058b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * check fail. The message is formed by replacing each {@code %s} 2068b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * placeholder in the template with an argument. These are matched by 2078b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. 2088b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Unmatched arguments will be appended to the formatted message in square 2098b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * braces. Unmatched placeholders will be left as-is. 2108b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param errorMessageArgs the arguments to be substituted into the message 2118b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * template. Arguments are converted to strings using 2128b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * {@link String#valueOf(Object)}. 2138b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @return the non-null reference that was validated 2148b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws NullPointerException if {@code reference} is null 2158b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 2168b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static <T> T checkNotNull(T reference, String errorMessageTemplate, 2178b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira Object... errorMessageArgs) { 2188b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (reference == null) { 2198b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira // If either of these parameters is null, the right thing happens anyway 2208b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new NullPointerException( 2218b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira format(errorMessageTemplate, errorMessageArgs)); 2228b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 2238b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return reference; 2248b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 2258b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 2268b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /* 2278b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * All recent hotspots (as of 2009) *really* like to have the natural code 2288b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2298b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * if (guardExpression) { 2308b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * throw new BadException(messageExpression); 2318b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * } 2328b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2338b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * refactored so that messageExpression is moved to a separate 2348b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * String-returning method. 2358b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2368b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * if (guardExpression) { 2378b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * throw new BadException(badMsg(...)); 2388b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * } 2398b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2408b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * The alternative natural refactorings into void or Exception-returning 2418b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * methods are much slower. This is a big deal - we're talking factors of 2428b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2-8 in microbenchmarks, not just 10-20%. (This is a hotspot optimizer 2438b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * bug, which should be fixed, but that's a separate, big project). 2448b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2458b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * The coding pattern above is heavily used in java.util, e.g. in ArrayList. 2468b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * There is a RangeCheckMicroBenchmark in the JDK that was used to test this. 2478b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2488b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * But the methods in this class want to throw different exceptions, 2498b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * depending on the args, so it appears that this pattern is not directly 2508b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * applicable. But we can use the ridiculous, devious trick of throwing an 2518b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * exception in the middle of the construction of another exception. 2528b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Hotspot is fine with that. 2538b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 2548b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 2558b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 2568b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures that {@code index} specifies a valid <i>element</i> in an array, 2578b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * list or string of size {@code size}. An element index may range from zero, 2588b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * inclusive, to {@code size}, exclusive. 2598b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2608b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param index a user-supplied index identifying an element of an array, list 2618b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * or string 2628b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param size the size of that array, list or string 2638b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @return the value of {@code index} 2648b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IndexOutOfBoundsException if {@code index} is negative or is not 2658b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * less than {@code size} 2668b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 2678b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 2688b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static int checkElementIndex(int index, int size) { 2698b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return checkElementIndex(index, size, "index"); 2708b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 2718b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 2728b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 2738b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures that {@code index} specifies a valid <i>element</i> in an array, 2748b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * list or string of size {@code size}. An element index may range from zero, 2758b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * inclusive, to {@code size}, exclusive. 2768b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 2778b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param index a user-supplied index identifying an element of an array, list 2788b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * or string 2798b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param size the size of that array, list or string 2808b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param desc the text to use to describe this index in an error message 2818b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @return the value of {@code index} 2828b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IndexOutOfBoundsException if {@code index} is negative or is not 2838b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * less than {@code size} 2848b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 2858b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 2868b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static int checkElementIndex(int index, int size, String desc) { 2878b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira // Carefully optimized for execution by hotspot (explanatory comment above) 2888b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (index < 0 || index >= size) { 2898b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); 2908b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 2918b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return index; 2928b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 2938b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 2948b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira private static String badElementIndex(int index, int size, String desc) { 2958b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (index < 0) { 2968b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return format("%s (%s) must not be negative", desc, index); 2978b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } else if (size < 0) { 2988b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IllegalArgumentException("negative size: " + size); 2998b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } else { // index >= size 3008b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return format("%s (%s) must be less than size (%s)", desc, index, size); 3018b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3028b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3038b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 3048b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 3058b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures that {@code index} specifies a valid <i>position</i> in an array, 3068b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * list or string of size {@code size}. A position index may range from zero 3078b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * to {@code size}, inclusive. 3088b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 3098b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param index a user-supplied index identifying a position in an array, list 3108b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * or string 3118b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param size the size of that array, list or string 3128b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @return the value of {@code index} 3138b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IndexOutOfBoundsException if {@code index} is negative or is 3148b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * greater than {@code size} 3158b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 3168b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 3178b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static int checkPositionIndex(int index, int size) { 3188b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return checkPositionIndex(index, size, "index"); 3198b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3208b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 3218b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 3228b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures that {@code index} specifies a valid <i>position</i> in an array, 3238b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * list or string of size {@code size}. A position index may range from zero 3248b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * to {@code size}, inclusive. 3258b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 3268b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param index a user-supplied index identifying a position in an array, list 3278b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * or string 3288b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param size the size of that array, list or string 3298b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param desc the text to use to describe this index in an error message 3308b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @return the value of {@code index} 3318b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IndexOutOfBoundsException if {@code index} is negative or is 3328b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * greater than {@code size} 3338b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 3348b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 3358b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static int checkPositionIndex(int index, int size, String desc) { 3368b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira // Carefully optimized for execution by hotspot (explanatory comment above) 3378b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (index < 0 || index > size) { 3388b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); 3398b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3408b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return index; 3418b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3428b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 3438b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira private static String badPositionIndex(int index, int size, String desc) { 3448b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (index < 0) { 3458b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return format("%s (%s) must not be negative", desc, index); 3468b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } else if (size < 0) { 3478b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IllegalArgumentException("negative size: " + size); 3488b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } else { // index > size 3498b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return format("%s (%s) must not be greater than size (%s)", 3508b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira desc, index, size); 3518b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3528b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3538b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 3548b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 3558b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Ensures that {@code start} and {@code end} specify a valid <i>positions</i> 3568b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * in an array, list or string of size {@code size}, and are in order. A 3578b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * position index may range from zero to {@code size}, inclusive. 3588b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 3598b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param start a user-supplied index identifying a starting position in an 3608b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * array, list or string 3618b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param end a user-supplied index identifying a ending position in an array, 3628b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * list or string 3638b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param size the size of that array, list or string 3648b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IndexOutOfBoundsException if either index is negative or is 3658b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * greater than {@code size}, or if {@code end} is less than {@code start} 3668b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @throws IllegalArgumentException if {@code size} is negative 3678b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 3688b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira public static void checkPositionIndexes(int start, int end, int size) { 3698b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira // Carefully optimized for execution by hotspot (explanatory comment above) 3708b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (start < 0 || end < start || end > size) { 3718b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); 3728b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3738b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3748b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 3758b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira private static String badPositionIndexes(int start, int end, int size) { 3768b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (start < 0 || start > size) { 3778b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return badPositionIndex(start, size, "start index"); 3788b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3798b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (end < 0 || end > size) { 3808b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return badPositionIndex(end, size, "end index"); 3818b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3828b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira // end < start 3838b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return format("end index (%s) must not be less than start index (%s)", 3848b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira end, start); 3858b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 3868b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 3878b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira /** 3888b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * Substitutes each {@code %s} in {@code template} with an argument. These 3898b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * are matched by position - the first {@code %s} gets {@code args[0]}, etc. 3908b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * If there are more arguments than placeholders, the unmatched arguments will 3918b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * be appended to the end of the formatted message in square braces. 3928b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * 3938b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param template a non-null string containing 0 or more {@code %s} 3948b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * placeholders. 3958b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * @param args the arguments to be substituted into the message 3968b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * template. Arguments are converted to strings using 3978b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira * {@link String#valueOf(Object)}. Arguments can be null. 3988b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira */ 3998b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira static String format(String template, Object... args) { 4008b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira // start substituting the arguments into the '%s' placeholders 4018b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira StringBuilder builder = new StringBuilder( 4028b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira template.length() + 16 * args.length); 4038b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira int templateStart = 0; 4048b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira int i = 0; 4058b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira while (i < args.length) { 4068b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira int placeholderStart = template.indexOf("%s", templateStart); 4078b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (placeholderStart == -1) { 4088b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira break; 4098b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 4108b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira builder.append(template.substring(templateStart, placeholderStart)); 4118b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira builder.append(args[i++]); 4128b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira templateStart = placeholderStart + 2; 4138b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 4148b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira builder.append(template.substring(templateStart)); 4158b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 4168b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira // if we run out of placeholders, append the extra args in square braces 4178b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira if (i < args.length) { 4188b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira builder.append(" ["); 4198b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira builder.append(args[i++]); 4208b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira while (i < args.length) { 4218b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira builder.append(", "); 4228b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira builder.append(args[i++]); 4238b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 4248b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira builder.append("]"); 4258b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 4268b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira 4278b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira return builder.toString(); 4288b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira } 4298b99ba451db6973978e60f91da2199686a9c85e7Mindy Pereira} 430