# HG changeset patch # User psandoz # Date 1444224163 -7200 # Node ID 7e1bb9268b8af979c6ccd51b165ef600b7dfc8db # Parent a3f03999ed622c337ef7329001a17a5974588b44 8135248: Add utility methods to check indexes and ranges Reviewed-by: forax, chegar, scolebourne, jrose, darcy diff -r a3f03999ed62 -r 7e1bb9268b8a jdk/src/java.base/share/classes/java/lang/ArrayIndexOutOfBoundsException.java --- a/jdk/src/java.base/share/classes/java/lang/ArrayIndexOutOfBoundsException.java Tue Oct 06 18:39:26 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/ArrayIndexOutOfBoundsException.java Wed Oct 07 15:22:43 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,42 +26,58 @@ package java.lang; /** - * Thrown to indicate that an array has been accessed with an - * illegal index. The index is either negative or greater than or - * equal to the size of the array. + * Thrown to indicate that an array has been accessed with an illegal index. The + * index is either negative or greater than or equal to the size of the array. * - * @author unascribed - * @since 1.0 + * @since 1.0 */ -public -class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException { +public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException { private static final long serialVersionUID = -5116101128118950844L; /** - * Constructs an ArrayIndexOutOfBoundsException with no - * detail message. + * Constructs an {@code ArrayIndexOutOfBoundsException} with no detail + * message. */ public ArrayIndexOutOfBoundsException() { super(); } /** - * Constructs a new ArrayIndexOutOfBoundsException - * class with an argument indicating the illegal index. + * Constructs an {@code ArrayIndexOutOfBoundsException} class with the + * specified detail message. * - * @param index the illegal index. + * @param s the detail message. + */ + public ArrayIndexOutOfBoundsException(String s) { + super(s); + } + + /** + * Constructs a new {@code ArrayIndexOutOfBoundsException} class with an + * argument indicating the illegal index. + * + *

The index is included in this exception's detail message. The + * exact presentation format of the detail message is unspecified. + * + * @param index the illegal index. */ public ArrayIndexOutOfBoundsException(int index) { super("Array index out of range: " + index); } /** - * Constructs an ArrayIndexOutOfBoundsException class - * with the specified detail message. + * Constructs a new {@code ArrayIndexOutOfBoundsException} class with + * arguments indicating two out of bound values. + * + *

The out of bound values are included in this exception's detail + * message. The exact presentation format of the detail message is + * unspecified. * - * @param s the detail message. + * @param a the first out of bound value. + * @param b the second out of bound value. + * @since 9 */ - public ArrayIndexOutOfBoundsException(String s) { - super(s); + public ArrayIndexOutOfBoundsException(int a, int b) { + super("Array indexed access out of bounds: " + a + ", " + b); } } diff -r a3f03999ed62 -r 7e1bb9268b8a jdk/src/java.base/share/classes/java/lang/IndexOutOfBoundsException.java --- a/jdk/src/java.base/share/classes/java/lang/IndexOutOfBoundsException.java Tue Oct 06 18:39:26 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/IndexOutOfBoundsException.java Wed Oct 07 15:22:43 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,28 +31,57 @@ *

* Applications can subclass this class to indicate similar exceptions. * - * @author Frank Yellin - * @since 1.0 + * @author Frank Yellin + * @since 1.0 */ -public -class IndexOutOfBoundsException extends RuntimeException { +public class IndexOutOfBoundsException extends RuntimeException { private static final long serialVersionUID = 234122996006267687L; /** - * Constructs an IndexOutOfBoundsException with no - * detail message. + * Constructs an {@code IndexOutOfBoundsException} with no detail message. */ public IndexOutOfBoundsException() { super(); } /** - * Constructs an IndexOutOfBoundsException with the - * specified detail message. + * Constructs an {@code IndexOutOfBoundsException} with the specified detail + * message. * - * @param s the detail message. + * @param s the detail message */ public IndexOutOfBoundsException(String s) { super(s); } + + /** + * Constructs a new {@code IndexOutOfBoundsException} class with an + * argument indicating the illegal index. + * + *

The index is included in this exception's detail message. The + * exact presentation format of the detail message is unspecified. + * + * @param index the illegal index. + * @since 9 + */ + public IndexOutOfBoundsException(int index) { + super("Index out of range: " + index); + } + + /** + * Constructs an {@code IndexOutOfBoundsException} with arguments indicating + * two out of bound values. + * + *

The out of bound values are included in this exception's detail + * message. The exact presentation format of the detail message is + * unspecified. + * + * @param a the first out of bound value + * @param b the second out of bound value + * @since 9 + */ + public IndexOutOfBoundsException(int a, int b) { + super("Indexed access out of bounds: " + a + ", " + b); + } + } diff -r a3f03999ed62 -r 7e1bb9268b8a jdk/src/java.base/share/classes/java/lang/StringIndexOutOfBoundsException.java --- a/jdk/src/java.base/share/classes/java/lang/StringIndexOutOfBoundsException.java Tue Oct 06 18:39:26 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/StringIndexOutOfBoundsException.java Wed Oct 07 15:22:43 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,44 +26,61 @@ package java.lang; /** - * Thrown by {@code String} methods to indicate that an index - * is either negative or greater than the size of the string. For - * some methods such as the charAt method, this exception also is - * thrown when the index is equal to the size of the string. + * Thrown by {@code String} methods to indicate that an index is either negative + * or greater than the size of the string. For some methods such as the + * {@link String#charAt charAt} method, this exception also is thrown when the + * index is equal to the size of the string. * - * @author unascribed - * @see java.lang.String#charAt(int) - * @since 1.0 + * @see java.lang.String#charAt(int) + * @since 1.0 */ -public -class StringIndexOutOfBoundsException extends IndexOutOfBoundsException { +public class StringIndexOutOfBoundsException extends IndexOutOfBoundsException { private static final long serialVersionUID = -6762910422159637258L; /** - * Constructs a {@code StringIndexOutOfBoundsException} with no - * detail message. + * Constructs a {@code StringIndexOutOfBoundsException} with no detail + * message. */ public StringIndexOutOfBoundsException() { super(); } /** - * Constructs a {@code StringIndexOutOfBoundsException} with - * the specified detail message. + * Constructs a {@code StringIndexOutOfBoundsException} with the specified + * detail message. * - * @param s the detail message. + * @param s the detail message. */ public StringIndexOutOfBoundsException(String s) { super(s); } /** - * Constructs a new {@code StringIndexOutOfBoundsException} - * class with an argument indicating the illegal index. + * Constructs a new {@code StringIndexOutOfBoundsException} class with an + * argument indicating the illegal index. * - * @param index the illegal index. + *

The index is included in this exception's detail message. The + * exact presentation format of the detail message is unspecified. + * + * @param index the illegal index. */ public StringIndexOutOfBoundsException(int index) { super("String index out of range: " + index); } + + /** + * Constructs a new {@code StringIndexOutOfBoundsException} class with + * arguments indicating two out of bound values. + * + *

The out of bound values are included in this exception's detail + * message. The exact presentation format of the detail message is + * unspecified. + * + * @param a the first out of bound value. + * @param b the second out of bound value. + * @since 9 + */ + public StringIndexOutOfBoundsException(int a, int b) { + super("String indexed access out of bounds: " + a + ", " + b); + } } diff -r a3f03999ed62 -r 7e1bb9268b8a jdk/src/java.base/share/classes/java/util/Objects.java --- a/jdk/src/java.base/share/classes/java/util/Objects.java Tue Oct 06 18:39:26 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/util/Objects.java Wed Oct 07 15:22:43 2015 +0200 @@ -25,13 +25,29 @@ package java.util; +import java.util.function.BiFunction; import java.util.function.Supplier; /** * This class consists of {@code static} utility methods for operating - * on objects. 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, and comparing two objects. + * 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. + * + * @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. + * 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 + * 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 + * functional interface allocation, may exceed the cost of checking bounds. * * @since 1.7 */ @@ -290,4 +306,230 @@ throw new NullPointerException(messageSupplier.get()); return obj; } + + /** + * 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's as if an exception mapping function was supplied that + * returns {@link IndexOutOfBoundsException} for any given arguments. + * @return the runtime exception + */ + private static RuntimeException outOfBounds( + int a, int b, BiFunction oobe) { + return oobe == null + ? new IndexOutOfBoundsException(a, b) + : oobe.apply(a, b); + } + + /** + * 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 + * following inequalities is true: + *

+ * + * @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 + * @since 9 + */ + public static + int checkIndex(int index, int length) throws IndexOutOfBoundsException { + return checkIndex(index, length, null); + } + + /** + * 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 + * following inequalities is true: + *

+ * + *

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. + * + * @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} + * then, it's as if an exception mapping function was supplied that + * returns {@link IndexOutOfBoundsException} for any given arguments. + * @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} + * @since 9 + */ + /* + @HotSpotIntrinsicCandidate + This method will be made intrinsic in C2 to guide HotSpot 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) + */ + public static + int checkIndex(int index, int length, + BiFunction oobe) throws T, IndexOutOfBoundsException { + if (index < 0 || index >= length) + throw outOfBounds(index, length, oobe); + return index; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@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 + * inequalities is true: + *

+ * + * @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 + * @since 9 + */ + public static + int checkFromToIndex(int fromIndex, int toIndex, int length) throws IndexOutOfBoundsException { + return checkFromToIndex(fromIndex, toIndex, length, null); + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@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 + * inequalities is true: + *

+ * + *

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. + * + * @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} + * then, it's as if an exception mapping function was supplied that + * returns {@link IndexOutOfBoundsException} for any given arguments. + * @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} + * @since 9 + */ + public static + int checkFromToIndex(int fromIndex, int toIndex, int length, + BiFunction oobe) throws T, IndexOutOfBoundsException { + if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) + throw outOfBounds(fromIndex, toIndex, oobe); + return fromIndex; + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@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 + * inequalities is true: + *

+ * + * @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 + * @since 9 + */ + public static + int checkFromIndexSize(int fromIndex, int size, int length) throws IndexOutOfBoundsException { + return checkFromIndexSize(fromIndex, size, length, null); + } + + /** + * Checks if the sub-range from {@code fromIndex} (inclusive) to + * {@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 + * inequalities is true: + *

+ * + *

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. + * + * @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} + * then, it's as if an exception mapping function was supplied that + * returns {@link IndexOutOfBoundsException} for any given arguments. + * @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} + * @since 9 + */ + public static + int checkFromIndexSize(int fromIndex, int size, int length, + BiFunction oobe) throws T, IndexOutOfBoundsException { + if ((length | fromIndex | size) < 0 || size > length - fromIndex) + throw outOfBounds(fromIndex, size, oobe); + return fromIndex; + } } diff -r a3f03999ed62 -r 7e1bb9268b8a jdk/test/java/util/Objects/CheckIndex.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/Objects/CheckIndex.java Wed Oct 07 15:22:43 2015 +0200 @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary IndexOutOfBoundsException check index tests + * @run testng CheckIndex + * @bug 8135248 + */ + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.IntSupplier; + +import static org.testng.Assert.*; + +public class CheckIndex { + + static class AssertingOutOfBoundsException extends RuntimeException { + } + + static BiFunction assertingOutOfBounds( + int expFromIndex, int expToIndexOrSizeOrLength) { + return (fromIndex, toIndexOrSizeorLength) -> { + assertEquals(fromIndex, Integer.valueOf(expFromIndex)); + assertEquals(toIndexOrSizeorLength, Integer.valueOf(expToIndexOrSizeOrLength)); + return new AssertingOutOfBoundsException(); + }; + } + + static final int[] VALUES = {0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, -1, Integer.MIN_VALUE + 1, Integer.MIN_VALUE}; + + @DataProvider + static Object[][] checkIndexProvider() { + List l = new ArrayList<>(); + for (int index : VALUES) { + for (int length : VALUES) { + boolean withinBounds = index >= 0 && + length >= 0 && + index < length; + l.add(new Object[]{index, length, withinBounds}); + } + } + return l.toArray(new Object[0][0]); + } + + interface X { + int apply(int a, int b, int c); + } + + @Test(dataProvider = "checkIndexProvider") + public void testCheckIndex(int index, int length, boolean withinBounds) { + BiConsumer, IntSupplier> check = (ec, s) -> { + try { + int rIndex = s.getAsInt(); + if (!withinBounds) + fail(String.format( + "Index %d is out of bounds of [0, %d), but was reported to be within bounds", index, length)); + assertEquals(rIndex, index); + } + catch (RuntimeException e) { + assertTrue(ec.isInstance(e)); + if (withinBounds) + fail(String.format( + "Index %d is within bounds of [0, %d), but was reported to be out of bounds", index, length)); + } + }; + + check.accept(AssertingOutOfBoundsException.class, + () -> Objects.checkIndex(index, length, assertingOutOfBounds(index, length))); + check.accept(IndexOutOfBoundsException.class, + () -> Objects.checkIndex(index, length, null)); + check.accept(IndexOutOfBoundsException.class, + () -> Objects.checkIndex(index, length)); + } + + + @DataProvider + static Object[][] checkFromToIndexProvider() { + List l = new ArrayList<>(); + for (int fromIndex : VALUES) { + for (int toIndex : VALUES) { + for (int length : VALUES) { + boolean withinBounds = fromIndex >= 0 && + toIndex >= 0 && + length >= 0 && + fromIndex <= toIndex && + toIndex <= length; + l.add(new Object[]{fromIndex, toIndex, length, withinBounds}); + } + } + } + return l.toArray(new Object[0][0]); + } + + @Test(dataProvider = "checkFromToIndexProvider") + public void testCheckFromToIndex(int fromIndex, int toIndex, int length, boolean withinBounds) { + BiConsumer, IntSupplier> check = (ec, s) -> { + try { + int rIndex = s.getAsInt(); + if (!withinBounds) + fail(String.format( + "Range [%d, %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, toIndex, length)); + assertEquals(rIndex, fromIndex); + } + catch (RuntimeException e) { + assertTrue(ec.isInstance(e)); + if (withinBounds) + fail(String.format( + "Range [%d, %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, toIndex, length)); + } + }; + + check.accept(AssertingOutOfBoundsException.class, + () -> Objects.checkFromToIndex(fromIndex, toIndex, length, assertingOutOfBounds(fromIndex, toIndex))); + check.accept(IndexOutOfBoundsException.class, + () -> Objects.checkFromToIndex(fromIndex, toIndex, length, null)); + check.accept(IndexOutOfBoundsException.class, + () -> Objects.checkFromToIndex(fromIndex, toIndex, length)); + } + + + @DataProvider + static Object[][] checkFromIndexSizeProvider() { + List l = new ArrayList<>(); + for (int fromIndex : VALUES) { + for (int size : VALUES) { + for (int length : VALUES) { + // Explicitly convert to long + long lFromIndex = fromIndex; + long lSize = size; + long lLength = length; + // Avoid overflow + long lToIndex = lFromIndex + lSize; + + boolean withinBounds = lFromIndex >= 0L && + lSize >= 0L && + lLength >= 0L && + lFromIndex <= lToIndex && + lToIndex <= lLength; + l.add(new Object[]{fromIndex, size, length, withinBounds}); + } + } + } + return l.toArray(new Object[0][0]); + } + + @Test(dataProvider = "checkFromIndexSizeProvider") + public void testCheckFromIndexSize(int fromIndex, int size, int length, boolean withinBounds) { + BiConsumer, IntSupplier> check = (ec, s) -> { + try { + int rIndex = s.getAsInt(); + if (!withinBounds) + fail(String.format( + "Range [%d, %d + %d) is out of bounds of [0, %d), but was reported to be withing bounds", fromIndex, fromIndex, size, length)); + assertEquals(rIndex, fromIndex); + } + catch (RuntimeException e) { + assertTrue(ec.isInstance(e)); + if (withinBounds) + fail(String.format( + "Range [%d, %d + %d) is within bounds of [0, %d), but was reported to be out of bounds", fromIndex, fromIndex, size, length)); + } + }; + + check.accept(AssertingOutOfBoundsException.class, + () -> Objects.checkFromIndexSize(fromIndex, size, length, assertingOutOfBounds(fromIndex, size))); + check.accept(IndexOutOfBoundsException.class, + () -> Objects.checkFromIndexSize(fromIndex, size, length, null)); + check.accept(IndexOutOfBoundsException.class, + () -> Objects.checkFromIndexSize(fromIndex, size, length)); + } + + @Test + public void checkIndexOutOfBoundsExceptionConstructors() { + BiConsumer, IntSupplier> check = (ec, s) -> { + try { + s.getAsInt(); + fail("Runtime exception expected"); + } + catch (RuntimeException e) { + assertTrue(ec.isInstance(e)); + } + }; + + check.accept(IndexOutOfBoundsException.class, + () -> Objects.checkIndex(1, 0, IndexOutOfBoundsException::new)); + check.accept(StringIndexOutOfBoundsException.class, + () -> Objects.checkIndex(1, 0, StringIndexOutOfBoundsException::new)); + check.accept(ArrayIndexOutOfBoundsException.class, + () -> Objects.checkIndex(1, 0, ArrayIndexOutOfBoundsException::new)); + } +}