为什么 IndexOutOfBoundsException 现在在 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);
}

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

数组必须按值编制索引;、或 值也可以用作索引值,因为它们受一元数字提升 (§5.6) 并成为值。intshortbytecharint

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

任何想法何时(以及为什么)将使用此索引构造函数?long


答案 1

引用评论以供将来参考:

这是由巴拿马项目促成的,它为Java带来了更好的本机堆访问。外部内存 API(直接字节缓冲区的替代品)允许对本机内存段进行长索引堆访问,从而促使对 IOOBE 进行此更改。– 布莱恩·戈茨

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

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

对象中的新方法是:

公共静态长检查索引(长索引,长长度) 公共静态长检查FromToIndex(长从索引,长到索引,长长度) 公共静态长检查从索引大小(长从索引,长大小,长长度)

它们镜像 int 实用工具方法。

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

来自另一个关于这个主题的来源: JDK 16: 检查多头的索引和范围

在我的上一篇文章中,我描述了JDK 16抢先体验版本25中添加的日间支持。JDK-8255150(“添加实用程序方法来检查长索引和范围”)是用于添加实用程序方法来检查长索引和范围的增强功能,类似于JDK-8135248(“添加实用程序方法来检查索引和范围”)为JDK 9的整数添加的实用程序方法。JDK-8255150指出,“目标是添加一组类似的方法(如JDK-8135248),但新方法不是对int参数进行操作,而是对长参数进行操作。

这些新添加的长期支持方法的最大受益者可能是外部内存访问API的作者,维护者和用户,如以下邮件列表消息中所述:“我们必须在实现外部内存访问API时跳过相当多的箍,以便利用基于int的索引检查的内延化, 即使这样,我们也没有涵盖数字大于整数的情况。期待能够删除这些黑客!


答案 2

我在OpenJdk中发现了另一个与该更改相关的票证。如前所述

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

对 Java 平台的增强将允许在大于 int 值的最小和最大范围的边界上优化循环,要求对长值进行边界检查。

在外部内存访问 API (JEP 393) 中,内存段的边界表示为长值。由于目前尚未优化涉及 long 的绑定检查,因此外部内存访问 API 的实现不得不采用几种技巧来衡量内存段是否可以被视为“小”(例如,其大小适合 int 值),然后相应地在小段上使用 int 操作。虽然在大多数情况下,这些解决方法隐藏在API实现中,但它们在复杂性和长期维护方面增加了显着的成本。

解决方案 重载在 java.util.对象中定义的现有 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)

以下构造函数被添加到 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 问题:添加实用工具方法来检查长索引和范围