diff -r 52d3d8517efc -r 9cb6e1141bdb jdk/src/java.base/share/classes/java/util/Objects.java --- a/jdk/src/java.base/share/classes/java/util/Objects.java Wed Apr 13 15:05:49 2016 +0200 +++ b/jdk/src/java.base/share/classes/java/util/Objects.java Wed Apr 13 15:05:50 2016 +0200 @@ -25,26 +25,28 @@ package java.util; +import jdk.internal.HotSpotIntrinsicCandidate; + import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Supplier; -import jdk.internal.HotSpotIntrinsicCandidate; /** * This class consists of {@code static} utility methods for operating * on objects, or checking certain conditions before operation. These utilities * include {@code null}-safe or {@code null}-tolerant methods for computing the * hash code of an object, returning a string for an object, comparing two - * objects, and checking if indexes or sub-range values are out of bounds. + * objects, and checking if indexes or sub-range values are out-of-bounds. * * @apiNote * Static methods such as {@link Objects#checkIndex}, * {@link Objects#checkFromToIndex}, and {@link Objects#checkFromIndexSize} are * provided for the convenience of checking if values corresponding to indexes - * and sub-ranges are out of bounds. + * and sub-ranges are out-of-bounds. * Variations of these static methods support customization of the runtime * exception, and corresponding exception detail message, that is thrown when - * values are out of bounds. Such methods accept a functional interface - * argument, instances of {@code BiFunction}, that maps out of bound values to a + * values are out-of-bounds. Such methods accept a functional interface + * argument, instances of {@code BiFunction}, that maps out-of-bound values to a * runtime exception. Care should be taken when using such methods in * combination with an argument that is a lambda expression, method reference or * class that capture values. In such cases the cost of capture, related to @@ -347,29 +349,176 @@ } /** - * Maps out of bounds values to a runtime exception. + * Maps out-of-bounds values to a runtime exception. * - * @param a the first out of bound value - * @param b the second out of bound value - * @param oobe the exception mapping function that when applied with out of - * bounds arguments returns a runtime exception. If {@code null} - * then, it is as if an exception mapping function was supplied that - * returns {@link IndexOutOfBoundsException} for any given arguments. + * @param checkKind the kind of bounds check, whose name may correspond + * to the name of one of the range check methods, checkIndex, + * checkFromToIndex, checkFromIndexSize + * @param args the out-of-bounds arguments that failed the range check. + * If the checkKind corresponds a the name of a range check method + * then the bounds arguments are those that can be passed in order + * to the method. + * @param oobef the exception formatter that when applied with a checkKind + * and a list out-of-bounds arguments returns a runtime exception. + * If {@code null} then, it is as if an exception formatter was + * supplied that returns {@link IndexOutOfBoundsException} for any + * given arguments. * @return the runtime exception */ private static RuntimeException outOfBounds( - int a, int b, BiFunction oobe) { - RuntimeException e = oobe == null - ? null : oobe.apply(a, b); + BiFunction, ? extends RuntimeException> oobef, + String checkKind, + Integer... args) { + List largs = List.of(args); + RuntimeException e = oobef == null + ? null : oobef.apply(checkKind, largs); return e == null - ? new IndexOutOfBoundsException(a, b) : e; + ? new IndexOutOfBoundsException(outOfBoundsMessage(checkKind, largs)) : e; + } + + // Specific out-of-bounds exception producing methods that avoid + // the varargs-based code in the critical methods there by reducing their + // the byte code size, and therefore less likely to peturb inlining + + private static RuntimeException outOfBoundsCheckIndex( + BiFunction, ? extends RuntimeException> oobe, + int index, int length) { + return outOfBounds(oobe, "checkIndex", index, length); + } + + private static RuntimeException outOfBoundsCheckFromToIndex( + BiFunction, ? extends RuntimeException> oobe, + int fromIndex, int toIndex, int length) { + return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length); + } + + private static RuntimeException outOfBoundsCheckFromIndexSize( + BiFunction, ? extends RuntimeException> oobe, + int fromIndex, int size, int length) { + return outOfBounds(oobe, "checkFromIndexSize", fromIndex, size, length); + } + + /** + * Returns an out-of-bounds exception formatter from an given exception + * factory. The exception formatter is a function that formats an + * out-of-bounds message from its arguments and applies that message to the + * given exception factory to produce and relay an exception. + * + *

The exception formatter accepts two arguments: a {@code String} + * describing the out-of-bounds range check that failed, referred to as the + * check kind; and a {@code List} containing the + * out-of-bound integer values that failed the check. The list of + * out-of-bound values is not modified. + * + *

Three check kinds are supported {@code checkIndex}, + * {@code checkFromToIndex} and {@code checkFromIndexSize} corresponding + * respectively to the specified application of an exception formatter as an + * argument to the out-of-bounds range check methods + * {@link #checkIndex(int, int, BiFunction) checkIndex}, + * {@link #checkFromToIndex(int, int, int, BiFunction) checkFromToIndex}, and + * {@link #checkFromIndexSize(int, int, int, BiFunction) checkFromIndexSize}. + * Thus a supported check kind corresponds to a method name and the + * out-of-bound integer values correspond to method argument values, in + * order, preceding the exception formatter argument (similar in many + * respects to the form of arguments required for a reflective invocation of + * such a range check method). + * + *

Formatter arguments conforming to such supported check kinds will + * produce specific exception messages describing failed out-of-bounds + * checks. Otherwise, more generic exception messages will be produced in + * any of the following cases: the check kind is supported but fewer + * or more out-of-bounds values are supplied, the check kind is not + * supported, the check kind is {@code null}, or the list of out-of-bound + * values is {@code null}. + * + * @apiNote + * This method produces an out-of-bounds exception formatter that can be + * passed as an argument to any of the supported out-of-bounds range check + * methods declared by {@code Objects}. For example, a formatter producing + * an {@code ArrayIndexOutOfBoundsException} may be produced and stored on a + * {@code static final} field as follows: + *

{@code
+     * static final
+     * BiFunction, ArrayIndexOutOfBoundsException> AIOOBEF =
+     *     outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
+     * }
+ * The formatter instance {@code AIOOBEF} may be passed as an argument to an + * out-of-bounds range check method, such as checking if an {@code index} + * is within the bounds of a {@code limit}: + *
{@code
+     * checkIndex(index, limit, AIOOBEF);
+     * }
+ * If the bounds check fails then the range check method will throw an + * {@code ArrayIndexOutOfBoundsException} with an appropriate exception + * message that is a produced from {@code AIOOBEF} as follows: + *
{@code
+     * AIOOBEF.apply("checkIndex", List.of(index, limit));
+     * }
+ * + * @param f the exception factory, that produces an exception from a message + * where the message is produced and formatted by the returned + * exception formatter. If this factory is stateless and side-effect + * free then so is the returned formatter. + * Exceptions thrown by the factory are relayed to the caller + * of the returned formatter. + * @param the type of runtime exception to be returned by the given + * exception factory and relayed by the exception formatter + * @return the out-of-bounds exception formatter + */ + public static + BiFunction, X> outOfBoundsExceptionFormatter(Function f) { + // Use anonymous class to avoid bootstrap issues if this method is + // used early in startup + return new BiFunction, X>() { + @Override + public X apply(String checkKind, List args) { + return f.apply(outOfBoundsMessage(checkKind, args)); + } + }; + } + + private static String outOfBoundsMessage(String checkKind, List args) { + if (checkKind == null && args == null) { + return String.format("Range check failed"); + } else if (checkKind == null) { + return String.format("Range check failed: %s", args); + } else if (args == null) { + return String.format("Range check failed: %s", checkKind); + } + + int argSize = 0; + switch (checkKind) { + case "checkIndex": + argSize = 2; + break; + case "checkFromToIndex": + case "checkFromIndexSize": + argSize = 3; + break; + default: + } + + // Switch to default if fewer or more arguments than required are supplied + switch ((args.size() != argSize) ? "" : checkKind) { + case "checkIndex": + return String.format("Index %d out-of-bounds for length %d", + args.get(0), args.get(1)); + case "checkFromToIndex": + return String.format("Range [%d, %d) out-of-bounds for length %d", + args.get(0), args.get(1), args.get(2)); + case "checkFromIndexSize": + return String.format("Range [%d, %The {@code index} is defined to be out of bounds if any of the + *

The {@code index} is defined to be out-of-bounds if any of the * following inequalities is true: *

    *
  • {@code index < 0}
  • @@ -377,14 +526,20 @@ *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* + *

This method behaves as if {@link #checkIndex(int, int, BiFunction)} + * was called with same out-of-bounds arguments and an exception formatter + * argument produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} (though it may + * be more efficient). + * * @param index the index * @param length the upper-bound (exclusive) of the range * @return {@code index} if it is within bounds of the range - * @throws IndexOutOfBoundsException if the {@code index} is out of bounds + * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds * @since 9 */ public static - int checkIndex(int index, int length) throws IndexOutOfBoundsException { + int checkIndex(int index, int length) { return checkIndex(index, length, null); } @@ -392,7 +547,7 @@ * Checks if the {@code index} is within the bounds of the range from * {@code 0} (inclusive) to {@code length} (exclusive). * - *

The {@code index} is defined to be out of bounds if any of the + *

The {@code index} is defined to be out-of-bounds if any of the * following inequalities is true: *

    *
  • {@code index < 0}
  • @@ -400,40 +555,42 @@ *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* - *

If the {@code index} is out of bounds, then a runtime exception is - * thrown that is the result of applying the arguments {@code index} and - * {@code length} to the given exception mapping function. + *

If the {@code index} is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkIndex}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code index} and {@code length}. * - * @param the type of runtime exception to throw if the arguments are - * out of bounds + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds * @param index the index * @param length the upper-bound (exclusive) of the range - * @param oobe the exception mapping function that when applied with out - * of bounds arguments returns a runtime exception. If {@code null} - * or returns {@code null} then, it is as if an exception mapping - * function was supplied that returns - * {@link IndexOutOfBoundsException} for any given arguments. - * Exceptions thrown by the function are relayed to the caller. + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. * @return {@code index} if it is within bounds of the range - * @throws T if the {@code index} is out of bounds, then a runtime exception - * is thrown that is the result of applying the out of bounds - * arguments to the exception mapping function. - * @throws IndexOutOfBoundsException if the {@code index} is out of bounds - * and the exception mapping function is {@code null} + * @throws X if the {@code index} is out-of-bounds and the exception + * formatter is non-{@code null} + * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds + * and the exception formatter is {@code null} * @since 9 * * @implNote - * This method is made intrinsic in optimizing compilers to guide - * them to perform unsigned comparisons of the index and length - * when it is known the length is a non-negative value (such as - * that of an array length or from the upper bound of a loop) + * This method is made intrinsic in optimizing compilers to guide them to + * perform unsigned comparisons of the index and length when it is known the + * length is a non-negative value (such as that of an array length or from + * the upper bound of a loop) */ @HotSpotIntrinsicCandidate - public static + public static int checkIndex(int index, int length, - BiFunction oobe) throws T, IndexOutOfBoundsException { + BiFunction, X> oobef) { if (index < 0 || index >= length) - throw outOfBounds(index, length, oobe); + throw outOfBoundsCheckIndex(oobef, index, length); return index; } @@ -442,7 +599,7 @@ * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} * (inclusive) to {@code length} (exclusive). * - *

The sub-range is defined to be out of bounds if any of the following + *

The sub-range is defined to be out-of-bounds if any of the following * inequalities is true: *

    *
  • {@code fromIndex < 0}
  • @@ -451,15 +608,21 @@ *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* + *

This method behaves as if {@link #checkFromToIndex(int, int, int, BiFunction)} + * was called with same out-of-bounds arguments and an exception formatter + * argument produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} (though it may + * be more efficient). + * * @param fromIndex the lower-bound (inclusive) of the sub-range * @param toIndex the upper-bound (exclusive) of the sub-range * @param length the upper-bound (exclusive) the range * @return {@code fromIndex} if the sub-range within bounds of the range - * @throws IndexOutOfBoundsException if the sub-range is out of bounds + * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds * @since 9 */ public static - int checkFromToIndex(int fromIndex, int toIndex, int length) throws IndexOutOfBoundsException { + int checkFromToIndex(int fromIndex, int toIndex, int length) { return checkFromToIndex(fromIndex, toIndex, length, null); } @@ -468,7 +631,7 @@ * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} * (inclusive) to {@code length} (exclusive). * - *

The sub-range is defined to be out of bounds if any of the following + *

The sub-range is defined to be out-of-bounds if any of the following * inequalities is true: *

    *
  • {@code fromIndex < 0}
  • @@ -477,34 +640,36 @@ *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* - *

If the sub-range is out of bounds, then a runtime exception is thrown - * that is the result of applying the arguments {@code fromIndex} and - * {@code toIndex} to the given exception mapping function. + *

If the sub-range is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromToIndex}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code toIndex}, and {@code length}. * - * @param the type of runtime exception to throw if the arguments are - * out of bounds + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds * @param fromIndex the lower-bound (inclusive) of the sub-range * @param toIndex the upper-bound (exclusive) of the sub-range * @param length the upper-bound (exclusive) the range - * @param oobe the exception mapping function that when applied with out - * of bounds arguments returns a runtime exception. If {@code null} - * or returns {@code null} then, it is as if an exception mapping - * function was supplied that returns - * {@link IndexOutOfBoundsException} for any given arguments. - * Exceptions thrown by the function are relayed to the caller. + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. * @return {@code fromIndex} if the sub-range within bounds of the range - * @throws T if the sub-range is out of bounds, then a runtime exception is - * thrown that is the result of applying the out of bounds arguments - * to the exception mapping function. - * @throws IndexOutOfBoundsException if the sub-range is out of bounds and - * the exception mapping function is {@code null} + * @throws X if the sub-range is out-of-bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and + * the exception factory function is {@code null} * @since 9 */ - public static + public static int checkFromToIndex(int fromIndex, int toIndex, int length, - BiFunction oobe) throws T, IndexOutOfBoundsException { + BiFunction, X> oobef) { if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) - throw outOfBounds(fromIndex, toIndex, oobe); + throw outOfBoundsCheckFromToIndex(oobef, fromIndex, toIndex, length); return fromIndex; } @@ -513,7 +678,7 @@ * {@code fromIndex + size} (exclusive) is within the bounds of range from * {@code 0} (inclusive) to {@code length} (exclusive). * - *

The sub-range is defined to be out of bounds if any of the following + *

The sub-range is defined to be out-of-bounds if any of the following * inequalities is true: *

    *
  • {@code fromIndex < 0}
  • @@ -522,15 +687,21 @@ *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* + *

This method behaves as if {@link #checkFromIndexSize(int, int, int, BiFunction)} + * was called with same out-of-bounds arguments and an exception formatter + * argument produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} (though it may + * be more efficient). + * * @param fromIndex the lower-bound (inclusive) of the sub-interval * @param size the size of the sub-range * @param length the upper-bound (exclusive) of the range * @return {@code fromIndex} if the sub-range within bounds of the range - * @throws IndexOutOfBoundsException if the sub-range is out of bounds + * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds * @since 9 */ public static - int checkFromIndexSize(int fromIndex, int size, int length) throws IndexOutOfBoundsException { + int checkFromIndexSize(int fromIndex, int size, int length) { return checkFromIndexSize(fromIndex, size, length, null); } @@ -539,7 +710,7 @@ * {@code fromIndex + size} (exclusive) is within the bounds of range from * {@code 0} (inclusive) to {@code length} (exclusive). * - *

The sub-range is defined to be out of bounds if any of the following + *

The sub-range is defined to be out-of-bounds if any of the following * inequalities is true: *

    *
  • {@code fromIndex < 0}
  • @@ -548,34 +719,37 @@ *
  • {@code length < 0}, which is implied from the former inequalities
  • *
* - *

If the sub-range is out of bounds then, a runtime exception is thrown - * that is the result of applying the arguments {@code fromIndex} and - * {@code size} to the given exception mapping function. + *

If the sub-range is out-of-bounds, then a runtime exception is + * thrown that is the result of applying the following arguments to the + * exception formatter: the name of this method, {@code checkFromIndexSize}; + * and an unmodifiable list integers whose values are, in order, the + * out-of-bounds arguments {@code fromIndex}, {@code size}, and + * {@code length}. * - * @param the type of runtime exception to throw if the arguments are - * out of bounds + * @param the type of runtime exception to throw if the arguments are + * out-of-bounds * @param fromIndex the lower-bound (inclusive) of the sub-interval * @param size the size of the sub-range * @param length the upper-bound (exclusive) of the range - * @param oobe the exception mapping function that when applied with out - * of bounds arguments returns a runtime exception. If {@code null} - * or returns {@code null} then, it is as if an exception mapping - * function was supplied that returns - * {@link IndexOutOfBoundsException} for any given arguments. - * Exceptions thrown by the function are relayed to the caller. + * @param oobef the exception formatter that when applied with this + * method name and out-of-bounds arguments returns a runtime + * exception. If {@code null} or returns {@code null} then, it is as + * if an exception formatter produced from an invocation of + * {@code outOfBoundsExceptionFormatter(IndexOutOfBounds::new)} is used + * instead (though it may be more efficient). + * Exceptions thrown by the formatter are relayed to the caller. * @return {@code fromIndex} if the sub-range within bounds of the range - * @throws T if the sub-range is out of bounds, then a runtime exception is - * thrown that is the result of applying the out of bounds arguments - * to the exception mapping function. - * @throws IndexOutOfBoundsException if the sub-range is out of bounds and - * the exception mapping function is {@code null} + * @throws X if the sub-range is out-of-bounds and the exception factory + * function is non-{@code null} + * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds and + * the exception factory function is {@code null} * @since 9 */ - public static + public static int checkFromIndexSize(int fromIndex, int size, int length, - BiFunction oobe) throws T, IndexOutOfBoundsException { + BiFunction, X> oobef) { if ((length | fromIndex | size) < 0 || size > length - fromIndex) - throw outOfBounds(fromIndex, size, oobe); + throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length); return fromIndex; } }