--- 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<Integer, Integer, ? extends RuntimeException> oobe) {
- RuntimeException e = oobe == null
- ? null : oobe.apply(a, b);
+ BiFunction<String, List<Integer>, ? extends RuntimeException> oobef,
+ String checkKind,
+ Integer... args) {
+ List<Integer> 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<String, List<Integer>, ? extends RuntimeException> oobe,
+ int index, int length) {
+ return outOfBounds(oobe, "checkIndex", index, length);
+ }
+
+ private static RuntimeException outOfBoundsCheckFromToIndex(
+ BiFunction<String, List<Integer>, ? extends RuntimeException> oobe,
+ int fromIndex, int toIndex, int length) {
+ return outOfBounds(oobe, "checkFromToIndex", fromIndex, toIndex, length);
+ }
+
+ private static RuntimeException outOfBoundsCheckFromIndexSize(
+ BiFunction<String, List<Integer>, ? 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.
+ *
+ * <p>The exception formatter accepts two arguments: a {@code String}
+ * describing the out-of-bounds range check that failed, referred to as the
+ * <em>check kind</em>; and a {@code List<Integer>} containing the
+ * out-of-bound integer values that failed the check. The list of
+ * out-of-bound values is not modified.
+ *
+ * <p>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).
+ *
+ * <p>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:
+ * <pre>{@code
+ * static final
+ * BiFunction<String, List<Integer>, ArrayIndexOutOfBoundsException> AIOOBEF =
+ * outOfBoundsExceptionFormatter(ArrayIndexOutOfBoundsException::new);
+ * }</pre>
+ * 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}:
+ * <pre>{@code
+ * checkIndex(index, limit, AIOOBEF);
+ * }</pre>
+ * 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:
+ * <pre>{@code
+ * AIOOBEF.apply("checkIndex", List.of(index, limit));
+ * }</pre>
+ *
+ * @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 <X> 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 <X extends RuntimeException>
+ BiFunction<String, List<Integer>, X> outOfBoundsExceptionFormatter(Function<String, X> f) {
+ // Use anonymous class to avoid bootstrap issues if this method is
+ // used early in startup
+ return new BiFunction<String, List<Integer>, X>() {
+ @Override
+ public X apply(String checkKind, List<Integer> args) {
+ return f.apply(outOfBoundsMessage(checkKind, args));
+ }
+ };
+ }
+
+ private static String outOfBoundsMessage(String checkKind, List<Integer> 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, %<d + %d) out-of-bounds for length %d",
+ args.get(0), args.get(1), args.get(2));
+ default:
+ return String.format("Range check failed: %s %s", checkKind, args);
+ }
}
/**
* Checks if the {@code index} is within the bounds of the range from
* {@code 0} (inclusive) to {@code length} (exclusive).
*
- * <p>The {@code index} is defined to be out of bounds if any of the
+ * <p>The {@code index} is defined to be out-of-bounds if any of the
* following inequalities is true:
* <ul>
* <li>{@code index < 0}</li>
@@ -377,14 +526,20 @@
* <li>{@code length < 0}, which is implied from the former inequalities</li>
* </ul>
*
+ * <p>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).
*
- * <p>The {@code index} is defined to be out of bounds if any of the
+ * <p>The {@code index} is defined to be out-of-bounds if any of the
* following inequalities is true:
* <ul>
* <li>{@code index < 0}</li>
@@ -400,40 +555,42 @@
* <li>{@code length < 0}, which is implied from the former inequalities</li>
* </ul>
*
- * <p>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.
+ * <p>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 <T> the type of runtime exception to throw if the arguments are
- * out of bounds
+ * @param <X> 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 <T extends RuntimeException>
+ public static <X extends RuntimeException>
int checkIndex(int index, int length,
- BiFunction<Integer, Integer, T> oobe) throws T, IndexOutOfBoundsException {
+ BiFunction<String, List<Integer>, 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).
*
- * <p>The sub-range is defined to be out of bounds if any of the following
+ * <p>The sub-range is defined to be out-of-bounds if any of the following
* inequalities is true:
* <ul>
* <li>{@code fromIndex < 0}</li>
@@ -451,15 +608,21 @@
* <li>{@code length < 0}, which is implied from the former inequalities</li>
* </ul>
*
+ * <p>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).
*
- * <p>The sub-range is defined to be out of bounds if any of the following
+ * <p>The sub-range is defined to be out-of-bounds if any of the following
* inequalities is true:
* <ul>
* <li>{@code fromIndex < 0}</li>
@@ -477,34 +640,36 @@
* <li>{@code length < 0}, which is implied from the former inequalities</li>
* </ul>
*
- * <p>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.
+ * <p>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 <T> the type of runtime exception to throw if the arguments are
- * out of bounds
+ * @param <X> 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 <T extends RuntimeException>
+ public static <X extends RuntimeException>
int checkFromToIndex(int fromIndex, int toIndex, int length,
- BiFunction<Integer, Integer, T> oobe) throws T, IndexOutOfBoundsException {
+ BiFunction<String, List<Integer>, 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).
*
- * <p>The sub-range is defined to be out of bounds if any of the following
+ * <p>The sub-range is defined to be out-of-bounds if any of the following
* inequalities is true:
* <ul>
* <li>{@code fromIndex < 0}</li>
@@ -522,15 +687,21 @@
* <li>{@code length < 0}, which is implied from the former inequalities</li>
* </ul>
*
+ * <p>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).
*
- * <p>The sub-range is defined to be out of bounds if any of the following
+ * <p>The sub-range is defined to be out-of-bounds if any of the following
* inequalities is true:
* <ul>
* <li>{@code fromIndex < 0}</li>
@@ -548,34 +719,37 @@
* <li>{@code length < 0}, which is implied from the former inequalities</li>
* </ul>
*
- * <p>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.
+ * <p>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 <T> the type of runtime exception to throw if the arguments are
- * out of bounds
+ * @param <X> 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 <T extends RuntimeException>
+ public static <X extends RuntimeException>
int checkFromIndexSize(int fromIndex, int size, int length,
- BiFunction<Integer, Integer, T> oobe) throws T, IndexOutOfBoundsException {
+ BiFunction<String, List<Integer>, X> oobef) {
if ((length | fromIndex | size) < 0 || size > length - fromIndex)
- throw outOfBounds(fromIndex, size, oobe);
+ throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length);
return fromIndex;
}
}