Почему 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
.