为什么 IndexOutOfBoundsException 现在在 Java16 中有一个以长索引作为参数的构造函数?

Why does IndexOutOfBoundsException now have a constructor with a long index as a parameter in Java 16?

我正在检查 JDK 16 中 IndexOutOfBoundsException 的实现,我注意到引入了一个带有 long 索引的新构造函数:

/**
 * Constructs a new {@code IndexOutOfBoundsException} class with an
 * argument indicating the illegal index.
 *
 * <p>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 16
 */
public IndexOutOfBoundsException(long index) {
    super("Index out of range: " + index);
}

据我所知,数组索引通常是 int 值,这在 Language Specification section §10.4:

中得到了证实

Arrays must be indexed by int values; short, byte, or char values may also be used as index values because they are subjected to unary numeric promotion (§5.6) and become int values.

An attempt to access an array component with a long index value results in a compile-time error.

知道何时(以及为什么)使用此 long 索引构造函数吗?

引用评论供日后参考:

This was precipitated by Project Panama, which brings better native heap access to Java. The Foreign Memory API (a replacement for direct byte buffers) allows long-indexed heap access to native memory segments, motivating this change to IOOBE. – Brian Goetz

TL;DR 与以下功能增强相关(JDK-8255150):Add utility methods to check long indexes and ranges

Description
This is related to JDK-8135248. The goal is to add a similar set of methods but rather than operate on int arguments, the new methods operate on long arguments.

The new methods in Objects are:

public static long checkIndex(long index, long length) public static long checkFromToIndex(long fromIndex, long toIndex, long length) public static long checkFromIndexSize(long fromIndex, long size, long length)

They mirror the int utility methods.

As is the case with the int checkIndex(), the long checkIndex() method will be JIT compiled as an intrinsic. That allows the JIT to compile checkIndex to an unsigned comparison and properly recognize it as range check that then becomes a candidate for the existing range check optimizations. This has proven to be important for panama's MemorySegment and a prototype of this change (with some extra c2 improvements) showed that panama micro benchmark results improve significantly.

来自关于该主题的另一个来源:JDK 16: Checking Indexes and Ranges of Longs

In my last post, I described the day period support added with JDK 16 Early Access Build 25. That same build also added methods for checking indexes and ranges of long values, which is the subject of this post. JDK-8255150 (“Add utility methods to check long indexes and ranges”) is the Enhancement used to add utility methods for checking long indexes and ranges similar to what JDK-8135248 (“Add utility methods to check indexes and ranges”) added for integers with JDK 9. JDK-8255150 states, “The goal is to add a similar set of methods [as JDK-8135248] but rather than operate on int arguments, the new methods operate on long arguments.”

The greatest beneficiary of these newly added long-supporting methods may be the authors, maintainers, and users of the foreign memory access API as described in this mailing list message: “We have to jump through quite a few hoops in the implementation of the foreign memory access API in order to leverage the intrinsification of int-based index checks, and even then we are not covering the cases where the numbers are larger than ints. Looking forward to being able to remove those hacks!”

我在 OpenJdk 中找到了另一个与该更改相关的票证。如那里所述

Bounds checking is not difficult to write explicitly but it can be easy to make trivial mistakes, such as introducing overflow bugs. It is advantageous to consolidate such checks from a correctness and security/integrity perspective. Further more in certain cases it is an opportunity to optimize, via an intrinsic, certain checks and guide hotspot towards unsigned comparisons.

Enhancements to the Java platform will enable optimizations of loops over bounds greater than the minimum and maximum range of int values, requiring bounds checking operating on long values.

In the Foreign Memory Access API (JEP 393), the bounds of a memory segments are expressed as long values. Since bound checks involving longs are not currently optimized, the implementation of the foreign memory access API had to resort to several tricks to gauge whether a memory segment can be considered "small" (e.g. whose size fits in an int value) and then use int operations on small segments, accordingly. While in most cases, these workarounds are hidden inside the API implementation, they add a significant cost in terms of complexity and long term maintenance.

Solution Overload the existing int accepting bounds check methods defined in java.util.Objects with long accepting bounds check methods.

java.util.Objects 添加了以下静态方法。该规范与现有 int 接受相同方法名称的边界检查方法的规范相同。

/**
 * 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
 * following inequalities is true:
 * <ul>
 *  <li>{@code index < 0}</li>
 *  <li>{@code index >= length}</li>
 *  <li>{@code length < 0}, which is implied from the former inequalities</li>
 * </ul>
 *
 * @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 16
 */
public static
long checkIndex(long index, long length)

/**
 * 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).
 *
 * <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>
 *  <li>{@code fromIndex > toIndex}</li>
 *  <li>{@code toIndex > length}</li>
 *  <li>{@code length < 0}, which is implied from the former inequalities</li>
 * </ul>
 *
 * @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 16
 */
public static
long checkFromToIndex(long fromIndex, long toIndex, long length)

/**
 * 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).
 *
 * <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>
 *  <li>{@code size < 0}</li>
 *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
 *  <li>{@code length < 0}, which is implied from the former inequalities</li>
 * </ul>
 *
 * @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 16
 */
public static
long checkFromIndexSize(long fromIndex, long size, long length)

The following constructor is added to java.lang.IndexOutOfBoundsException:

/**
 * Constructs a new {@code IndexOutOfBoundsException} class with an
 * argument indicating the illegal index.
 *
 * <p>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 16
 */
public IndexOutOfBoundsException(long index)

Jira 问题:Add utility methods to check long indexes and ranges

一个IndexOutOfBoundsException不一定只在访问数组时抛出(有子类ArrayIndexOutOfBoundsException)或一个List;您可以从您自己的任何代码中抛出它,允许用户编写的 类 或第三方库抛出 IndexOutOfBoundsException 似乎是合理的,即使它们的索引是 long 而不是 int.