Почему IndexOutOfBoundsException с длинным индексом в Java 16?

Я проверял реализацию IndexOutOfBoundsException в JDK 16 и заметил, что был введен новый конструктор с индексом:

      /**
 * 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);
}

Насколько мне известно, индексы массива обычно являются значениями, и это подтверждено в Спецификации языка :

Массивы необходимо индексировать по значениям; short, byte, или же char значения могут также использоваться как значения индекса, потому что они подвергаются унарному числовому продвижению (§5.6) и становятся int значения.

Попытка получить доступ к компоненту массива со значением индекса приводит к ошибке времени компиляции.

Любая идея, когда это long конструктор индекса будет использоваться или зачем он нужен?

3 ответа

Решение

TL;DR Это связано со следующим улучшением функции (JDK-8255150): добавление служебных методов для проверки длинных индексов и диапазонов

Описание
Это связано с JDK-8135248. Цель состоит в том, чтобы добавить аналогичный набор методов, но вместо того, чтобы работать с аргументами типа int, новые методы работают с длинными аргументами.

Новые методы в объектах:

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

Они отражают служебные методы int.

Как и в случае с int checkIndex(), длинный метод checkIndex() будет JIT-скомпилирован как внутренний. Это позволяет JIT компилировать checkIndex в беззнаковое сравнение и правильно распознавать его как проверку диапазона, которая затем становится кандидатом для существующей оптимизации проверки диапазона. Это оказалось важным для PanamaMemorySegment, и прототип этого изменения (с некоторыми дополнительными улучшениями c2) показал, что результаты микро-теста Panama значительно улучшились.

Из другого источника по теме: JDK 16: Проверка индексов и диапазонов длинных позиций :

В моем последнем посте я описал поддержку дневного периода, добавленную в JDK 16Early Access Build 25. Эта же сборка также добавила методы для проверки индексов и диапазонов длинных значений, что является предметом этого поста.JDK-8255150 («Добавить служебные методы для проверки длинных индексов и диапазонов») - это расширение, используемое для добавления служебных методов для проверки длинных индексов и диапазонов, аналогично тому, что JDK-8135248 («Добавить служебные методы для проверки индексов и диапазонов») добавлено для целые числа с JDK 9.JDK-8255150 утверждает: «Цель состоит в том, чтобы добавить аналогичный набор методов [как JDK-8135248], но вместо того, чтобы работать с аргументами типа int, новые методы работают с длинными аргументами».

Наибольшую выгоду от этих недавно добавленных давно поддерживаемых методов могут быть авторы, специалисты по сопровождению и пользователи API доступа к внешней памяти, как описано в этом сообщении списка рассылки: «Мы должны преодолеть немало препятствий в реализации внешнего интерфейса. API доступа к памяти, чтобы использовать встроенную проверку индексов на основе int, и даже в этом случае мы не рассматриваем случаи, когда числа больше, чем int. С нетерпением жду возможности удалить эти взломы! »

Я нашел еще один билет в OpenJdk, который имеет отношение к этому изменению. Как сказано там

Проверку границ несложно написать явно, но можно легко сделать тривиальные ошибки, например, внести ошибки переполнения. Такие проверки выгодно объединить с точки зрения правильности и безопасности / целостности. Более того, в некоторых случаях это возможность оптимизировать через внутренние определенные проверки и направить точку доступа к беззнаковым сравнениям.

Усовершенствования платформы Java позволят оптимизировать циклы по границам, превышающим минимальный и максимальный диапазон значений int, требуя проверки границ, работающей с длинными значениями.

В API доступа к внешней памяти (JEP 393) границы сегментов памяти выражаются как длинные значения . Поскольку связанные проверки с использованием long в настоящее время не оптимизированы, реализация API доступа к внешней памяти должна была прибегнуть к нескольким приемам, чтобы определить, можно ли считать сегмент памяти «маленьким» (например, чей размер соответствует значению int), а затем использовать int соответственно операции на небольших участках. Хотя в большинстве случаев эти обходные пути скрыты внутри реализации API, они добавляют значительные затраты с точки зрения сложности и длительного обслуживания.

Решение Перегрузите существующие методы проверки принимающих границ int, определенные в java.util.Objects, методами проверки длинных принимающих границ.

Спецификация В 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: добавление служебных методов для проверки длинных индексов и диапазонов

Не обязательно выдается только при доступе к массиву (есть подкласс ArrayIndexOutOfBoundsException для этого) или List; вы можете выбросить его из любого собственного кода, и кажется разумным разрешить пользовательским классам или сторонним библиотекам бросать IndexOutOfBoundsException даже если их индексы long скорее, чем int.

Другие вопросы по тегам