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

man*_*uti 29 java arrays indexoutofboundsexception long-integer 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);
}
Run Code Online (Sandbox Code Playgroud)

据我所知,数组索引通常是int值,这在语言规范部分 §10.4 中得到证实:

数组必须按int值索引;shortbyte、 或char值也可以用作索引值,因为它们经过一元数字提升(第 5.6 节)并成为int值。

尝试使用long索引值访问数组组件会导致编译时错误。

知道什么时候(以及为什么)long会使用这个索引构造函数吗?

dre*_*ash 29

引用评论以供将来参考:

这是由 Project Panama 促成的,它为 Java 带来了更好的本地堆访问。外部内存 API(直接字节缓冲区的替代品)允许对本机内存段进行长索引堆访问,从而推动了对 IOOBE 的这种更改。— 布赖恩·戈茨

TL;DR它与以下功能增强 (JDK-8255150) 相关:添加实用方法来检查长索引和范围

描述
这与 JDK-8135248 相关。目标是添加一组类似的方法,但不是对 int 参数进行操作,而是对长参数进行操作。

Objects 中的新方法是:

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)

它们反映了 int 实用程序方法。

与 int checkIndex() 的情况一样,long checkIndex() 方法将被 JIT 编译为内部函数。这允许 JIT 将 checkIndex 编译为无符号比较,并将其正确识别为范围检查,然后成为现有范围检查优化的候选者。这已被证明对巴拿马的 MemorySegment 很重要,并且此更改的原型(带有一些额外的 c2 改进)表明巴拿马微基准测试结果显着改善。

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

在我的上一篇博文中,我描述了 JDK 16 Early Access Build 25 添加的日间周期支持。同一个版本还添加了检查索引和长值范围的方法,这是本文的主题。JDK-8255150(“添加用于检查长索引和范围的实用方法”)是用于添加用于检查长索引和范围的实用方法的增强功​​能,类似于 JDK-8135248(“添加用于检查索引和范围的实用方法”)为JDK 9 中的整数。JDK-8255150 指出,“目标是添加一组类似的方法 [如 JDK-8135248],但新方法不是对 int 参数进行操作,而是对长参数进行操作。”

这些新增加的长期支持方法的最大受益者可能是作者,维护者,以及国外的存储器访问的API在这个邮件列表消息中描述的用户:“我们在国外执行过不少跳火圈内存访问 API 以利用基于 int 的索引检查的内在化,即使如此,我们也不涵盖数字大于 int 的情况。期待能够删除这些黑客!”


Pan*_*kos 14

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

明确地编写边界检查并不难,但很容易犯一些小错误,例如引入溢出错误。从正确性和安全性/完整性的角度整合此类检查是有利的。此外,在某些情况下,它是通过内在的某些检查和引导热点进行无符号比较的机会。

Java 平台的增强功能将使循环优化超过 int 值的最小和最大范围,需要对 long 值进行边界检查。

在外部内存访问 API (JEP 393) 中,内存段的边界表示为 long values。由于涉及 longs 的边界检查目前尚未优化,因此外部内存访问 API 的实现不得不求助于几个技巧来判断内存段是否可以被认为是“小”的(例如,其大小适合一个 int 值),然后使用 int相应地,对小细分市场进行操作。虽然在大多数情况下,这些变通方法隐藏在 API 实现中,但它们在复杂性和长期维护方面增加了大量成本。

解决方案 使用长接受边界检查方法重载 java.util.Objects 中定义的现有 int 接受边界检查方法。

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)
Run Code Online (Sandbox Code Playgroud)

下面的构造函数被添加到 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)
Run Code Online (Sandbox Code Playgroud)

Jira 问题:添加实用方法来检查长索引和范围


kay*_*ya3 7

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