Spec-Zone.ru › OpenJDK 25

Класс MethodHandles

java.lang.Object
java.lang.invoke.MethodHandles
public final class MethodHandles extends Object
Этот класс состоит исключительно из статических методов, работающих с дескрипторами методов или возвращающих их. Они относятся к нескольким категориям:
  • Методы поиска, помогающие создавать дескрипторы методов для методов и полей.
  • Методы-комбинаторы, объединяющие или преобразующие существующие дескрипторы методов в новые.
  • Другие фабричные методы для создания дескрипторов методов, имитирующих распространённые операции JVM или шаблоны управления потоком выполнения.
Метод поиска, метод-комбинатор или фабричный метод завершится ошибкой и выбросит IllegalArgumentException, если тип созданного дескриптора метода будет содержать слишком много параметров.
Начиная с версии:
1.7

Краткое описание вложенных классов

Модификатор и тип Класс Описание
static final class  MethodHandles.Lookup
Объект поиска — это фабрика для создания дескрипторов методов в случаях, когда при создании требуется проверка доступа.

Краткое описание методов

Модификатор и тип Метод Описание
static MethodHandle arrayConstructor(Class<?> arrayClass)
Создаёт дескриптор метода, конструирующий массивы заданного типа, как если бы использовался байткод anewarray.
static MethodHandle arrayElementGetter(Class<?> arrayClass)
Создаёт дескриптор метода, предоставляющий доступ для чтения к элементам массива, как если бы использовался байткод aaload.
static MethodHandle arrayElementSetter(Class<?> arrayClass)
Создаёт дескриптор метода, предоставляющий доступ для записи к элементам массива, как если бы использовался байткод astore.
static VarHandle arrayElementVarHandle(Class<?> arrayClass)
Создаёт VarHandle, предоставляющий доступ к элементам массива типа arrayClass.
static MethodHandle arrayLength(Class<?> arrayClass)
Создаёт дескриптор метода, возвращающий длину массива, как если бы использовался байткод arraylength.
static VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder)
Создаёт VarHandle, предоставляющий доступ к элементам массива byte[], рассматриваемого как массив другого примитивного типа, например int[] или long[].
static VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder)
Создаёт VarHandle, предоставляющий доступ к элементам ByteBuffer, рассматриваемого как массив элементов другого примитивного типа, отличного от типа компонента byte, например int[] или long[].
static MethodHandle catchException(MethodHandle target, Class<? extends Throwable> exType, MethodHandle handler)
Создаёт дескриптор метода, адаптирующий целевой дескриптор метода путём его выполнения внутри обработчика исключений.
static <T> T classData(MethodHandles.Lookup caller, String name, Class<T> type)
Возвращает данные класса, связанные с классом поиска заданного объекта поиска caller, или null.
static <T> T classDataAt(MethodHandles.Lookup caller, String name, Class<T> type, int index)
Возвращает элемент с указанным индексом в данных класса, если данные класса, связанные с классом поиска заданного объекта поиска caller, имеют тип List.
static MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter)
Адаптирует целевой дескриптор метода, предварительно обрабатывая подпоследовательность его аргументов с помощью фильтра (другого дескриптора метода).
static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter)
Адаптирует целевой var handle, предварительно обрабатывая подпоследовательность его координатных значений с помощью фильтра (дескриптора метода).
static MethodHandle constant(Class<?> type, Object value)
Создаёт дескриптор метода с запрошенным типом возвращаемого значения, который при каждом вызове возвращает заданное постоянное значение.
static MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body)
Создаёт цикл, выполняющий заданное число итераций.
static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body)
Создаёт цикл, перебирающий диапазон чисел.
static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred)
Создаёт цикл do-while из инициализатора, тела и предиката.
static MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
Создаёт дескриптор метода, который отбрасывает некоторые фиктивные аргументы перед вызовом другого заданного дескриптора метода цели.
static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)
Создаёт дескриптор метода, который отбрасывает некоторые фиктивные аргументы перед вызовом другого заданного дескриптора метода цели.
static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos)
Адаптирует целевой дескриптор метода к заданному списку типов параметров.
static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes)
Возвращает var handle, который отбрасывает некоторые фиктивные координаты перед передачей управления целевому var handle.
static MethodHandle dropReturn(MethodHandle target)
Отбрасывает возвращаемое значение целевого дескриптора (если оно есть).
static MethodHandle empty(MethodType type)
Создаёт дескриптор метода запрошенного типа, который игнорирует любые аргументы, ничего не делает и возвращает подходящее значение по умолчанию в зависимости от типа возвращаемого значения.
static MethodHandle exactInvoker(MethodType type)
Создаёт специальный дескриптор метода-вызовитель, который можно использовать для вызова любого дескриптора метода заданного типа, как если бы применялся invokeExact.
static MethodHandle explicitCastArguments(MethodHandle target, MethodType newType)
Создаёт дескриптор метода, адаптирующий тип заданного дескриптора метода к новому типу путём попарного преобразования типов аргументов и возвращаемого значения.
static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters)
Адаптирует целевой дескриптор метода, предварительно обрабатывая один или несколько его аргументов, каждый с помощью собственной унарной функции-фильтра, а затем вызывая целевой дескриптор с заменой каждого обработанного аргумента результатом соответствующей функции-фильтра.
static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters)
Адаптирует целевой var handle, предварительно обрабатывая входящие координатные значения с помощью унарных функций-фильтров.
static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter)
Адаптирует целевой дескриптор метода, обрабатывая его возвращаемое значение (если оно есть) с помощью фильтра (другого дескриптора метода).
static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
Адаптирует целевой var handle, предварительно обрабатывая входящие и исходящие значения с помощью пары функций-фильтров.
static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner)
Адаптирует целевой дескриптор метода, предварительно обрабатывая некоторые его аргументы, начиная с заданной позиции, а затем вызывая целевой дескриптор, вставляя результат предварительной обработки в исходную последовательность аргументов непосредственно перед аргументами свёртки.
static MethodHandle foldArguments(MethodHandle target, MethodHandle combiner)
Адаптирует целевой дескриптор метода, предварительно обрабатывая некоторые его аргументы, а затем вызывая целевой дескриптор, вставляя результат предварительной обработки в исходную последовательность аргументов.
static MethodHandle guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)
Создаёт дескриптор метода, адаптирующий целевой дескриптор метода и защищающий его с помощью проверки — дескриптора метода, возвращающего логическое значение.
static MethodHandle identity(Class<?> type)
Создаёт дескриптор метода, который при вызове возвращает свой единственный аргумент.
static MethodHandle insertArguments(MethodHandle target, int pos, Object... values)
Заранее предоставляет целевому дескриптору метода один или несколько связанных аргументов для его вызова.
static VarHandle insertCoordinates(VarHandle target, int pos, Object... values)
Заранее предоставляет целевому var handle одну или несколько связанных координат для его вызова.
static MethodHandle invoker(MethodType type)
Создаёт специальный дескриптор метода-вызовитель, который можно использовать для вызова любого дескриптора метода, совместимого с заданным типом, как если бы применялся invoke.
static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body)
Создаёт цикл, перебирающий значения, полученные из Iterator<T>.
static MethodHandles.Lookup lookup()
Возвращает lookup object, обладающий всеми возможностями для имитации поддерживаемых операций байткода вызывающего кода.
static MethodHandle loop(MethodHandle[]... clauses)
Создаёт дескриптор метода, представляющий цикл с несколькими переменными цикла, которые обновляются и проверяются на каждой итерации.
static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder)
Создаёт дескриптор метода, адаптирующий последовательность вызова заданного дескриптора метода к новому типу путём переупорядочивания аргументов.
static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder)
Возвращает var handle, адаптирующий координатные значения целевого var handle путём их перестановки так, чтобы новые координаты соответствовали заданным.
static MethodHandles.Lookup privateLookupIn(Class<?> targetClass, MethodHandles.Lookup caller)
Возвращает объект lookup для целевого класса, чтобы имитировать все поддерживаемые операции байткода, включая доступ к закрытым членам.
static MethodHandles.Lookup publicLookup()
Возвращает lookup object с минимальным уровнем доверия.
static <T extends Member>
T
reflectAs(Class<T> expected, MethodHandle target)
Выполняет непроверенное «раскрытие» прямого дескриптора метода.
static MethodHandle spreadInvoker(MethodType type, int leadingArgCount)
Создаёт дескриптор метода, который вызывает любой дескриптор метода типа type, заменяя заданное число завершающих аргументов одним завершающим массивом Object[].
static MethodHandle tableSwitch(MethodHandle fallback, MethodHandle... targets)
Создаёт дескриптор метода переключения по таблице, который можно использовать для переключения между набором целевых дескрипторов методов на основе заданного целевого индекса, называемого селектором.
static MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType)
Создаёт дескриптор метода, который выбрасывает исключения заданного типа exType.
static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup)
Создаёт дескриптор метода, адаптирующий дескриптор метода target путём его обёртывания в блок try-finally.
static MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode, MethodType type)
Создаёт специальный дескриптор метода-вызовитель, который можно использовать для вызова метода режима доступа с полиморфной сигнатурой у любого VarHandle, связанный с которым тип режима доступа совместим с заданным типом.
static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type)
Создаёт специальный дескриптор метода-вызовитель, который можно использовать для вызова метода режима доступа с полиморфной сигнатурой у любого VarHandle, связанный с которым тип режима доступа совместим с заданным типом.
static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body)
Создаёт цикл while из инициализатора, тела и предиката.
static MethodHandle zero(Class<?> type)
Создаёт константный дескриптор метода с запрошенным типом возвращаемого значения, который при каждом вызове возвращает значение по умолчанию для этого типа.

Методы, объявленные в классе Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Подробное описание методов

lookup

public static MethodHandles.Lookup lookup()
Возвращает lookup object с полными возможностями для эмуляции всех поддерживаемых вариантов поведения байт-кода вызывающего кода. Эти возможности включают полный привилегированный доступ к вызывающему коду. Фабричные методы объекта поиска могут создавать прямые дескрипторы методов для любых элементов, к которым вызывающий код имеет доступ через байт-код, включая защищённые и закрытые поля и методы. Этот объект поиска создаётся исходным классом поиска и имеет установленный бит ORIGINAL. Этот объект поиска является полномочием, которое можно делегировать доверенным агентам. Не храните его там, где к нему может получить доступ недоверенный код.

Этот метод чувствителен к вызывающему коду, то есть может возвращать разные значения разным вызывающим сторонам. Если MethodHandles.lookup вызывается из контекста, в котором в стеке нет кадра вызывающего кода (например, при непосредственном вызове из присоединённого потока JNI), выбрасывается IllegalCallerException. Чтобы получить lookup object в таком контексте, используйте вспомогательный класс, который будет неявно определён как вызывающий код, или используйте publicLookup(), чтобы получить поиск с ограниченными привилегиями.

Возвращает:
объект поиска для вызывающего этот метод кода, с исходным и полным привилегированным доступом.
Выбрасывает:
IllegalCallerException — если в стеке нет кадра вызывающего кода.

publicLookup

public static MethodHandles.Lookup publicLookup()
Возвращает lookup object с минимальным уровнем доверия. Поиск имеет режим UNCONDITIONAL. Его можно использовать только для создания дескрипторов методов для открытых элементов открытых классов в пакетах, экспортируемых безусловно.

Согласно общепринятому соглашению, класс поиска этого объекта поиска будет Object.

Примечание API:
Использование Object основано на соглашении, а поскольку режимы поиска ограничены, специальный доступ к внутренним компонентам Object, его пакету или модулю не предоставляется. Этот общедоступный объект поиска или другой объект поиска с режимом UNCONDITIONAL предполагает доступность для чтения. Следовательно, класс поиска не используется для определения контекста поиска.

Обсуждение: Класс поиска можно изменить на любой другой класс C с помощью выражения вида publicLookup().in(C.class). Кроме того, он не может получать доступ к методам, чувствительным к вызывающему коду.

Возвращает:
объект поиска с минимальным уровнем доверия

privateLookupIn

public static MethodHandles.Lookup privateLookupIn(Class<?> targetClass, MethodHandles.Lookup caller) throws IllegalAccessException
Возвращает объект lookup для целевого класса, способный эмулировать все поддерживаемые варианты поведения байт-кода, включая закрытый доступ. Возвращённый объект поиска может предоставлять доступ к классам в модулях и пакетах, а также к элементам этих классов, за пределами обычных правил управления доступом в Java, следуя вместо этого более разрешительным правилам модульной глубокой рефлексии.

Вызывающему коду, представленному объектом Lookup, в модуле M1 разрешена глубокая рефлексия в модуле M2 и пакете целевого класса тогда и только тогда, когда выполняются все следующие условия true:

  • Объект поиска вызывающего кода должен иметь полный привилегированный доступ. В частности:
    • Объект поиска вызывающего кода должен иметь режим поиска MODULE. (Это необходимо, поскольку в противном случае нельзя было бы гарантировать, что исходный создатель объекта поиска является членом какого-либо конкретного модуля, и поэтому любые последующие проверки читаемости и квалифицированного экспорта оказались бы неэффективными.)
    • Объект поиска вызывающего кода должен иметь доступ PRIVATE. (Это необходимо, поскольку приложение, намеревающееся совместно использовать доступ внутри модуля только с помощью MODULE, непреднамеренно предоставит также доступ к глубокой рефлексии в собственном модуле.)
  • Целевой класс должен быть обычным классом, а не примитивным классом или массивом. (Таким образом, M2 определено.)
  • Если модуль вызывающего кода M1 отличается от целевого модуля M2, должны выполняться оба следующих условия:
    • M1 reads M2.
    • M2 opens пакет, содержащий целевой класс, как минимум для M1.

Если любое из указанных выше условий не выполняется, этот метод завершается исключением.

В противном случае, если M1 и M2 являются одним и тем же модулем, этот метод возвращает Lookup для targetClass с полным привилегированным доступом и null в качестве предыдущего класса поиска.

В противном случае M1 и M2 являются разными модулями. Этот метод возвращает Lookup для targetClass, в котором класс поиска вызывающего кода записан как новый предыдущий класс поиска, с доступом PRIVATE, но без доступа MODULE.

Полученный объект Lookup не имеет доступа ORIGINAL.

Примечание API:
Объект Lookup, возвращаемый этим методом, может определять классы в пакете времени выполнения класса targetClass. При открытии пакета другому модулю следует проявлять крайнюю осторожность, поскольку такие определённые классы имеют такой же полный привилегированный доступ, как и другие элементы модуля targetClass.
Параметры:
targetClass — целевой класс
caller — объект поиска вызывающего кода
Возвращает:
объект поиска для целевого класса с закрытым доступом
Выбрасывает:
IllegalArgumentException — если targetClass является примитивным типом, типом void или массивом
NullPointerException — если targetClass или caller равно null
IllegalAccessException — если любая из других описанных выше проверок доступа завершается неудачей
Начиная с версии:
9
См. также:
  • MethodHandles.Lookup.dropLookupMode(int)
  • Поиски между модулями

classData

public static <T> T classData(MethodHandles.Lookup caller, String name, Class<T> type) throws IllegalAccessException
Возвращает данные класса, связанные с классом поиска заданного объекта поиска caller, или null.

Скрытый класс с данными класса можно создать вызовом Lookup::defineHiddenClassWithClassData. Если статический инициализатор класса поиска заданного объекта поиска caller ещё не был выполнен, этот метод приведёт к его выполнению.

Скрытые классы, созданные с помощью Lookup::defineHiddenClass, и нескрытые классы не имеют данных класса. Если вызвать этот метод для объекта поиска этих классов, будет возвращено null.

Для получения данных класса режимы поиска этого объекта поиска должны включать исходный доступ.

Примечание API:
Этот метод можно вызывать как bootstrap-метод для динамически вычисляемой константы. Например, платформа может создать скрытый класс с данными класса, которые могут быть Class или объектом MethodHandle. Данные класса доступны только объекту поиска, созданному исходным вызывающим кодом, но недоступны другим элементам того же гнезда. Если платформа передаёт скрытому классу объекты, связанные с безопасностью, через данные класса, рекомендуется загружать значение данных класса как динамически вычисляемую константу, а не хранить данные класса в закрытых статических полях, доступных другим участникам гнезда.
Параметры типа:
T — тип, к которому следует привести объект данных класса
Параметры:
caller — контекст поиска, описывающий класс, выполняющий операцию (обычно помещается в стек JVM)
name — должно быть ConstantDescs.DEFAULT_NAME ("_")
type — тип данных класса
Возвращает:
значение данных класса, если они присутствуют в классе поиска; в противном случае — null
Выбрасывает:
IllegalArgumentException — если имя не равно "_"
IllegalAccessException — если контекст поиска не имеет исходного доступа
ClassCastException — если данные класса нельзя преобразовать к заданному типу type
NullPointerException — если аргумент caller или type равен null
См. Спецификацию виртуальной машины Java:
5.5 Инициализация
Начиная с версии:
16
См. также:
  • MethodHandles.Lookup.defineHiddenClassWithClassData(byte[], Object, boolean, Lookup.ClassOption...)
  • classDataAt(Lookup, String, Class, int)

classDataAt

public static <T> T classDataAt(MethodHandles.Lookup caller, String name, Class<T> type, int index) throws IllegalAccessException
Возвращает элемент по указанному индексу в данных класса, если данные класса, связанные с классом поиска заданного объекта поиска caller, имеют тип List. Если в этом классе поиска данные класса отсутствуют, метод возвращает null.

Скрытый класс с данными класса можно создать вызовом Lookup::defineHiddenClassWithClassData. Если статический инициализатор класса поиска заданного объекта поиска caller ещё не был выполнен, этот метод приведёт к его выполнению.

Скрытые классы, созданные с помощью Lookup::defineHiddenClass, и нескрытые классы не имеют данных класса. Если вызвать этот метод для объекта поиска этих классов, будет возвращено null.

Для получения данных класса режимы поиска этого объекта поиска должны включать исходный доступ.

Примечание API:
Этот метод можно вызывать как bootstrap-метод для динамически вычисляемой константы. Например, платформа может создать скрытый класс с данными класса, такими как List.of(o1, o2, o3....), содержащими несколько объектов, и использовать этот метод для загрузки элемента по заданному индексу. Данные класса доступны только объекту поиска, созданному исходным вызывающим кодом, но недоступны другим элементам того же гнезда. Если платформа передаёт скрытому классу объекты, связанные с безопасностью, через данные класса, рекомендуется загружать значение данных класса как динамически вычисляемую константу, а не хранить данные класса в закрытых статических полях, доступных другим участникам гнезда.
Параметры типа:
T — тип, к которому следует привести возвращаемый объект
Параметры:
caller — контекст поиска, описывающий класс, выполняющий операцию (обычно помещается в стек JVM)
name — должно быть ConstantDescs.DEFAULT_NAME ("_")
type — тип элемента по указанному индексу в данных класса
index — индекс элемента в данных класса
Возвращает:
элемент по заданному индексу в данных класса, если данные класса присутствуют; в противном случае — null
Выбрасывает:
IllegalArgumentException — если имя не равно "_"
IllegalAccessException — если контекст поиска не имеет исходного доступа
ClassCastException — если данные класса нельзя преобразовать к List или элемент по указанному индексу нельзя преобразовать к заданному типу
IndexOutOfBoundsException — если индекс выходит за допустимый диапазон
NullPointerException — если аргумент caller или type равен null; либо если операция распаковки завершается неудачей, поскольку элемент по заданному индексу имеет значение null
Начиная с версии:
16
См. также:
  • classData(Lookup, String, Class)
  • MethodHandles.Lookup.defineHiddenClassWithClassData(byte[], Object, boolean, Lookup.ClassOption...)

reflectAs

public static <T extends Member> T reflectAs(Class<T> expected, MethodHandle target)
Выполняет непроверяемое «раскрытие» прямого дескриптора метода. Результат эквивалентен тому, как если бы пользователь получил объект поиска с достаточными полномочиями для раскрытия целевого дескриптора метода, вызвал для целевого дескриптора Lookup.revealDirect, чтобы получить его символьную ссылку, а затем вызвал MethodHandleInfo.reflectAs, чтобы разрешить символьную ссылку в элемент.
Параметры типа:
T — требуемый тип результата: Member или его подтип
Параметры:
expected — объект класса, представляющий требуемый тип результата T
target — прямой дескриптор метода, который требуется раскрыть на компоненты символьной ссылки
Возвращает:
ссылку на объект метода, конструктора или поля
Выбрасывает:
NullPointerException — если любой из аргументов равен null
IllegalArgumentException — если цель не является прямым дескриптором метода
ClassCastException — если элемент не имеет ожидаемого типа
Начиная с версии:
1.8

arrayConstructor

public static MethodHandle arrayConstructor(Class<?> arrayClass) throws IllegalArgumentException
Создаёт дескриптор метода, конструирующий массивы заданного типа, как если бы использовался байт-код anewarray. Типом возвращаемого значения дескриптора метода будет тип массива. Типом его единственного аргумента будет int, задающий размер массива.

Если вызвать возвращённый дескриптор метода с отрицательным размером массива, будет выброшено исключение NegativeArraySizeException.

Параметры:
arrayClass — тип массива
Возвращает:
дескриптор метода, создающий массивы заданного типа
Выбрасывает:
NullPointerException — если аргумент равен null
IllegalArgumentException — если arrayClass не является типом массива
См. Спецификацию виртуальной машины Java:
6.5 Инструкция anewarray
Начиная с версии:
9
См. также:
  • Array.newInstance(Class, int)

arrayLength

public static MethodHandle arrayLength(Class<?> arrayClass) throws IllegalArgumentException
Создаёт дескриптор метода, возвращающий длину массива, как если бы использовался байт-код arraylength. Тип возвращаемого значения дескриптора метода — int, а его единственный аргумент имеет тип массива.

Если вызвать возвращённый дескриптор метода с ссылкой на массив null, будет выброшено исключение NullPointerException.

Параметры:
arrayClass — тип массива
Возвращает:
дескриптор метода, позволяющий получить длину массива заданного типа
Выбрасывает:
NullPointerException — если аргумент равен null
IllegalArgumentException — если arrayClass не является типом массива
См. Спецификацию виртуальной машины Java:
6.5 Инструкция arraylength
Начиная с версии:
9

arrayElementGetter

public static MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException
Создаёт дескриптор метода, предоставляющий доступ на чтение к элементам массива, как если бы использовался байт-код aaload. Тип возвращаемого значения дескриптора метода совпадает с типом элементов массива. Его первым аргументом будет тип массива, а вторым — int.

При вызове возвращённого дескриптора метода проверяются ссылка на массив и индекс массива. Если ссылка на массив равна null, будет выброшено исключение NullPointerException; если индекс отрицательный или больше либо равен длине массива, будет выброшено исключение ArrayIndexOutOfBoundsException.

Параметры:
arrayClass — тип массива
Возвращает:
дескриптор метода, позволяющий загружать значения из массива заданного типа
Выбрасывает:
NullPointerException — если аргумент равен null
IllegalArgumentException — если arrayClass не является типом массива
См. Спецификацию виртуальной машины Java:
6.5 Инструкция aaload

arrayElementSetter

public static MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException
Создаёт дескриптор метода, предоставляющий доступ на запись к элементам массива, как если бы использовался байт-код astore. Тип возвращаемого значения дескриптора метода — void. Его последним аргументом будет тип элементов массива. Первый и второй аргументы — тип массива и int.

При вызове возвращённого дескриптора метода проверяются ссылка на массив и индекс массива. Если ссылка на массив равна null, будет выброшено исключение NullPointerException; если индекс отрицательный или больше либо равен длине массива, будет выброшено исключение ArrayIndexOutOfBoundsException.

Параметры:
arrayClass — класс массива
Возвращает:
дескриптор метода, позволяющий сохранять значения в массив заданного типа
Выбрасывает:
NullPointerException — если аргумент равен null
IllegalArgumentException — если arrayClass не является типом массива
См. Спецификацию виртуальной машины Java:
6.5 Инструкция aastore

arrayElementVarHandle

public static VarHandle arrayElementVarHandle(Class<?> arrayClass) throws IllegalArgumentException
Создаёт VarHandle, предоставляющий доступ к элементам массива типа arrayClass. Тип переменной VarHandle — тип компонента arrayClass, а список типов координат — (arrayClass, int), где тип координаты int соответствует аргументу, задающему индекс в массиве.

При следующих условиях некоторые режимы доступа возвращённого VarHandle не поддерживаются:

  • если тип компонента не является byte, short, char, int, long, float или double, то режимы атомарного обновления числовых значений не поддерживаются.
  • если тип компонента не является boolean, byte, short, char, int или long, то режимы побитового атомарного обновления не поддерживаются.

Если тип компонента — float или double, то режимы числового и атомарного обновления сравнивают значения по их побитовому представлению (см. соответственно Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double)).

При вызове возвращённого VarHandle проверяются ссылка на массив и индекс массива. Если ссылка на массив равна null, будет выброшено исключение NullPointerException; если индекс отрицательный или больше либо равен длине массива, будет выброшено исключение ArrayIndexOutOfBoundsException.

Примечание API:
Побитовое сравнение значений float или double, выполняемое режимами числового и атомарного обновления, отличается от примитивного оператора == и методов Float.equals(Object) и Double.equals(Object), в частности, при сравнении значений NaN или сравнении -0.0 с +0.0. При выполнении операций compare-and-set или compare-and-exchange с такими значениями следует соблюдать осторожность, поскольку операция может неожиданно завершиться неудачей. В Java существует множество значений NaN, которые считаются NaN, хотя ни одна операция с плавающей запятой IEEE 754, предоставляемая Java, не может различить их. Операция может завершиться неудачей, если ожидаемое значение или значение-свидетель является NaN и преобразуется (возможно, специфичным для платформы способом) в другое значение NaN, имеющее иное побитовое представление (подробнее см. Float.intBitsToFloat(int) или Double.longBitsToDouble(long)). Значения -0.0 и +0.0 имеют разные побитовые представления, но считаются равными при использовании примитивного оператора ==. Например, операция может завершиться неудачей, если числовой алгоритм вычислит ожидаемое значение, скажем, -0.0, а ранее вычисленное значение-свидетель окажется, скажем, +0.0.
Параметры:
arrayClass — класс массива типа T[]
Возвращает:
VarHandle, предоставляющий доступ к элементам массива
Выбрасывает:
NullPointerException — если arrayClass равен null
IllegalArgumentException — если arrayClass не является типом массива
Начиная с версии:
9

byteArrayViewVarHandle

public static VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder) throws IllegalArgumentException
Создаёт VarHandle, предоставляющий доступ к элементам массива byte[], интерпретируемого как массив другого примитивного типа, например int[] или long[]. Тип переменной VarHandle — тип компонента viewArrayClass, а список типов координат — (byte[], int), где тип координаты int соответствует аргументу, задающему индекс в массиве byte[]. Возвращённый VarHandle обращается к байтам по индексу в массиве byte[] и объединяет байты в значение типа компонента viewArrayClass или разбивает его на байты согласно заданному порядку байтов.

Поддерживаемые типы компонентов (типы переменных): short, char, int, long, float и double.

Доступ к байтам по заданному индексу приведёт к ArrayIndexOutOfBoundsException, если индекс меньше 0 или больше длины массива byte[] за вычетом размера (в байтах) T.

Возвращённый VarHandle поддерживает только обычные режимы доступа get и set. Для всех остальных режимов доступа будет выброшено исключение UnsupportedOperationException.

Примечание API:
Если требуются режимы доступа, отличные от обычного доступа, клиентам следует рассмотреть возможность использования памяти вне кучи через прямые буферы байтов или сегменты памяти вне кучи, либо сегменты памяти, основанные на long[], для которых можно обеспечить более строгие гарантии выравнивания.
Параметры:
viewArrayClass — класс массива-представления с типом компонента T
byteOrder — порядок байтов элементов массива-представления, хранящихся в базовом массиве byte
Возвращает:
VarHandle, предоставляющий доступ к элементам массива byte[], интерпретируемого как элементы, соответствующие типу компонентов класса массива-представления
Выбрасывает:
NullPointerException — если viewArrayClass или byteOrder равен null
IllegalArgumentException — если viewArrayClass не является типом массива
UnsupportedOperationException — если тип компонента viewArrayClass не поддерживается в качестве типа переменной
Начиная с версии:
9

byteBufferViewVarHandle

public static VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder) throws IllegalArgumentException
Создаёт VarHandle, предоставляющий доступ к элементам ByteBuffer, рассматриваемого как массив элементов другого примитивного типа компонента, отличного от типа byte, например int[] или long[]. Тип переменной VarHandle — тип компонента viewArrayClass, а список типов координат — (ByteBuffer, int), где тип координаты int соответствует аргументу, который является индексом в массиве byte[]. Возвращаемый VarHandle обращается к байтам по индексу в ByteBuffer, объединяя байты в значение типа компонента viewArrayClass или разбивая его на байты в соответствии с заданным порядком байтов.

Поддерживаются следующие типы компонентов (типы переменных): short, char, int, long, float и double.

Если ByteBuffer доступен только для чтения, любая операция доступа, кроме режимов чтения, приведёт к ReadOnlyBufferException.

Доступ к байтам по заданному индексу приведёт к IndexOutOfBoundsException, если индекс меньше 0 или больше предельного значения ByteBuffer за вычетом размера (в байтах) T.

Для байтовых буферов в куче доступ всегда является невыровненным. В результате возвращаемый дескриптор переменной поддерживает только обычные режимы доступа get и set. Для всех остальных режимов доступа будет выброшено исключение IllegalStateException.

Только для прямых буферов доступ к байтам по индексу может быть выровненным или невыровненным для T относительно базового адреса памяти, то есть A, связанного с ByteBuffer и индексом. Если доступ невыровнен, то доступ в любом режиме, кроме режимов get и set, приведёт к IllegalStateException. В таких случаях атомарный доступ гарантируется только относительно наибольшей степени двойки, на которую делится НОД A и размера (в байтах) T. Если доступ выровнен, поддерживаются следующие режимы доступа, для которых гарантируется атомарный доступ:

  • режимы доступа для чтения и записи для всех T. Режимы доступа get и set для long и double поддерживаются, но не гарантируют атомарность, как описано в разделе 17.7 Спецификации языка Java.
  • режимы атомарного обновления для int, long, float или double. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные типы.)
  • режимы числового атомарного обновления для int и long. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные числовые типы.)
  • режимы побитового атомарного обновления для int и long. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные числовые типы.)

Невыровненный доступ и, следовательно, гарантии атомарности для ByteBuffer, bb (прямого или иного), index, T и соответствующего ему упакованного типа, T_BOX можно определить следующим образом:

int sizeOfT = T_BOX.BYTES;  // size in bytes of T
ByteBuffer bb = ...
int misalignedAtIndex = bb.alignmentOffset(index, sizeOfT);
boolean isMisaligned = misalignedAtIndex != 0;

Если тип переменной — float или double, то режимы атомарного обновления сравнивают значения по их битовому представлению (см. соответственно Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double)).

Параметры:
viewArrayClass — класс массива-представления с типом компонента T
byteOrder — порядок байтов элементов массива-представления, сохранённых в базовом ByteBuffer (обратите внимание: он имеет приоритет над порядком байтов в ByteBuffer)
Возвращает:
VarHandle, предоставляющий доступ к элементам ByteBuffer, рассматриваемого как элементы, соответствующие типу компонента класса массива-представления
Вызывает:
NullPointerException — если viewArrayClass или byteOrder равен null
IllegalArgumentException — если viewArrayClass не является типом массива
UnsupportedOperationException — если тип компонента viewArrayClass не поддерживается как тип переменной
С версии:
9

spreadInvoker

public static MethodHandle spreadInvoker(MethodType type, int leadingArgCount)
Создаёт дескриптор метода, который вызывает любой дескриптор метода заданного type, заменяя заданное количество конечных аргументов одним конечным массивом Object[]. Полученный дескриптор вызова будет иметь следующие аргументы:
  • одна целевая MethodHandle
  • ноль или более начальных значений (количество задаётся параметром leadingArgCount)
  • массив Object[], содержащий конечные аргументы

Дескриптор вызова вызывает свою цель так же, как вызов invoke с указанным type. То есть, если тип цели точно совпадает с заданным type, поведение будет таким же, как у invokeExact; в противном случае поведение будет таким, как если бы для преобразования цели к требуемому type использовался asType.

Тип возвращаемого дескриптора вызова не будет совпадать с заданным type: все параметры, кроме первых leadingArgCount, будут заменены одним массивом типа Object[], который станет последним параметром.

Перед вызовом цели дескриптор вызова развернёт конечный массив, при необходимости выполнит приведение ссылочных типов, а также распаковку и расширение примитивных аргументов. Если при вызове дескриптора переданный аргумент-массив содержит неверное количество элементов, дескриптор вызовет IllegalArgumentException вместо вызова цели.

Этот метод эквивалентен следующему коду (хотя может быть более эффективным):

MethodHandle invoker = MethodHandles.invoker(type);
int spreadArgCount = type.parameterCount() - leadingArgCount;
invoker = invoker.asSpreader(Object[].class, spreadArgCount);
return invoker;
Этот метод не вызывает рефлексивных исключений.
Параметры:
type — требуемый тип цели
leadingArgCount — количество фиксированных аргументов, передаваемых цели без изменений
Возвращает:
дескриптор метода, подходящий для вызова любого дескриптора метода заданного типа
Вызывает:
NullPointerException — если type равен null
IllegalArgumentException — если leadingArgCount не входит в диапазон от 0 до type.parameterCount() включительно или если тип полученного дескриптора метода будет содержать слишком много параметров

exactInvoker

public static MethodHandle exactInvoker(MethodType type)
Создаёт специальный дескриптор метода-вызова, который можно использовать для вызова любого дескриптора метода заданного типа, как если бы использовался invokeExact. Тип полученного дескриптора вызова будет в точности совпадать с требуемым типом, за исключением дополнительного начального аргумента типа MethodHandle.

Этот метод эквивалентен следующему коду (хотя может быть более эффективным): publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)

Обсуждение: Дескрипторы методов-вызовов могут быть полезны при работе с дескрипторами методов переменной, типы которых неизвестны. Например, чтобы эмулировать вызов invokeExact дескриптора метода переменной M, извлеките его тип T, найдите дескриптор метода-вызова X для T и вызовите этот дескриптор метода, как X.invoke(T, A...). Вызвать X.invokeExact не получится, поскольку тип T неизвестен. Если требуется развернуть, собрать или иным образом преобразовать аргументы, эти преобразования можно один раз применить к дескриптору вызова X и повторно использовать для множества значений дескриптора метода M, если они совместимы с типом X.

(Примечание: дескриптор метода-вызова недоступен через API базовой рефлексии. Попытка вызвать java.lang.reflect.Method.invoke для объявленного метода invokeExact или invoke приведёт к исключению UnsupportedOperationException.)

Этот метод не вызывает рефлексивных исключений.

Параметры:
type — требуемый тип цели
Возвращает:
дескриптор метода, подходящий для вызова любого дескриптора метода заданного типа
Вызывает:
IllegalArgumentException — если тип полученного дескриптора метода будет содержать слишком много параметров

invoker

public static MethodHandle invoker(MethodType type)
Создаёт специальный дескриптор метода-вызова, который можно использовать для вызова любого дескриптора метода, совместимого с заданным типом, как если бы использовался invoke. Тип полученного дескриптора вызова будет в точности совпадать с требуемым типом, за исключением дополнительного начального аргумента типа MethodHandle.

Перед вызовом цели, если её тип отличается от ожидаемого, дескриптор вызова при необходимости выполнит приведение ссылочных типов, упаковку, распаковку или расширение примитивных значений, как если бы использовался asType. Аналогичным образом при необходимости будет преобразовано возвращаемое значение. Если цель — дескриптор метода с переменной арностью, будет выполнено необходимое преобразование арности, опять же так, как если бы использовался asType.

Этот метод эквивалентен следующему коду (хотя может быть более эффективным): publicLookup().findVirtual(MethodHandle.class, "invoke", type)

Обсуждение: обобщённый тип метода содержит только аргументы и возвращаемые значения типа Object. Дескриптор вызова для такого типа способен вызывать любой дескриптор метода с той же арностью, что и у обобщённого типа.

(Примечание: дескриптор метода-вызова недоступен через API базовой рефлексии. Попытка вызвать java.lang.reflect.Method.invoke для объявленного метода invokeExact или invoke приведёт к исключению UnsupportedOperationException.)

Этот метод не вызывает рефлексивных исключений.

Параметры:
type — требуемый тип цели
Возвращает:
дескриптор метода, подходящий для вызова любого дескриптора метода, преобразуемого к заданному типу
Вызывает:
IllegalArgumentException — если тип полученного дескриптора метода будет содержать слишком много параметров

varHandleExactInvoker

public static MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode, MethodType type)
Создаёт специальный дескриптор метода-вызова, который можно использовать для вызова метода режима доступа с полиморфной сигнатурой у любого VarHandle, связанный тип режима доступа которого совместим с заданным типом. Тип полученного дескриптора вызова будет в точности совпадать с требуемым заданным типом, за исключением дополнительного начального аргумента типа VarHandle.
Параметры:
accessMode — режим доступа VarHandle
type — требуемый тип цели
Возвращает:
дескриптор метода, подходящий для вызова метода режима доступа любого VarHandle, тип режима доступа которого совпадает с заданным типом.
С версии:
9

varHandleInvoker

public static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type)
Создаёт специальный дескриптор метода-вызова, который можно использовать для вызова метода режима доступа с полиморфной сигнатурой у любого VarHandle, связанный тип режима доступа которого совместим с заданным типом. Тип полученного дескриптора вызова будет в точности совпадать с требуемым заданным типом, за исключением дополнительного начального аргумента типа VarHandle.

Перед вызовом цели, если тип режима доступа отличается от требуемого заданного типа, дескриптор вызова при необходимости выполнит приведение ссылочных типов, упаковку, распаковку или расширение примитивных значений, как если бы использовался asType. Аналогичным образом при необходимости будет преобразовано возвращаемое значение.

Этот метод эквивалентен следующему коду (хотя может быть более эффективным): publicLookup().findVirtual(VarHandle.class, accessMode.name(), type)

Параметры:
accessMode — режим доступа VarHandle
type — требуемый тип цели
Возвращает:
дескриптор метода, подходящий для вызова метода режима доступа любого VarHandle, тип режима доступа которого можно преобразовать к заданному типу.
С версии:
9

explicitCastArguments

public static MethodHandle explicitCastArguments(MethodHandle target, MethodType newType)
Создаёт дескриптор метода, адаптирующий тип заданного дескриптора метода к новому типу посредством попарного преобразования типов аргументов и возвращаемого значения. Исходный и новый типы должны иметь одинаковое количество аргументов. Гарантируется, что тип полученного дескриптора метода будет совпадать с требуемым новым типом.

Если исходный и новый типы совпадают, возвращает target.

Допускаются те же преобразования, что и для MethodHandle.asType; если эти преобразования невозможны, дополнительно применяются некоторые другие преобразования. Для заданных типов T0 и T1 перед любыми преобразованиями, выполняемыми методом asType, либо вместо них по возможности применяется одно из следующих преобразований:

  • Если T0 и T1 являются ссылочными типами, а T1 — типом интерфейса, значение типа T0 передаётся как T1 без приведения. (Такая обработка интерфейсов соответствует правилам верификатора байт-кода.)
  • Если T0 имеет тип boolean, а T1 — другой примитивный тип, значение boolean преобразуется в значение byte: 1 для true, 0 для false. (Такая обработка соответствует правилам верификатора байт-кода.)
  • Если T1 имеет тип boolean, а T0 — другой примитивный тип, T0 преобразуется в byte с помощью преобразования приведения Java (JLS 5.5), после чего проверяется младший бит результата, как если бы использовался (x & 1) != 0.
  • Если T0 и T1 — примитивные типы, отличные от boolean, применяется преобразование приведения Java (JLS 5.5). (В частности, преобразование T0 в T1 выполняется с расширением и/или сужением.)
  • Если T0 — ссылочный тип, а T1 — примитивный, во время выполнения применяется распаковка, за которой может следовать преобразование приведения Java (JLS 5.5) примитивного значения, а затем преобразование byte в boolean посредством проверки младшего бита.
  • Если T0 — ссылочный тип, а T1 — примитивный, и во время выполнения ссылка имеет значение null, вместо неё подставляется нулевое значение.
Параметры:
target — дескриптор метода, который нужно вызвать после изменения типов аргументов
newType — ожидаемый тип нового дескриптора метода
Возвращает:
дескриптор метода, который делегирует вызов цели после необходимых преобразований аргументов и выполняет необходимые преобразования возвращаемого значения
Вызывает:
NullPointerException — если любой из аргументов равен null
WrongMethodTypeException — если преобразование невозможно выполнить
См. также:
  • MethodHandle.asType(MethodType)

permuteArguments

public static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder)
Создаёт дескриптор метода, адаптирующий последовательность вызова заданного дескриптора метода к новому типу посредством перестановки аргументов. Гарантируется, что тип полученного дескриптора метода будет совпадать с требуемым новым типом.

Перестановка задаётся переданным массивом. Обозначим #I количество входящих параметров (значение newType.parameterCount()), а #O — количество исходящих параметров (значение target.type().parameterCount()). Тогда длина массива перестановки должна быть равна #O, а каждый его элемент должен быть неотрицательным числом, меньшим #I. Для каждого N, меньшего #O, исходящий аргумент с индексом N берётся из входящего аргумента с индексом I, где I — это reorder[N].

Преобразования аргументов и возвращаемого значения не выполняются. Тип каждого входящего аргумента, определяемый с помощью newType, должен совпадать с типом соответствующего исходящего параметра или параметров целевого дескриптора метода. Возвращаемый тип newType должен совпадать с возвращаемым типом исходной цели.

Массив перестановки не обязан задавать фактическую перестановку. Входящий аргумент будет продублирован, если его индекс встречается в массиве несколько раз, и отброшен, если его индекс в массиве отсутствует. Как и в случае с dropArguments, типы входящих аргументов, не упомянутых в массиве перестановки, могут быть любыми; они определяются только с помощью newType.

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodType intfn1 = methodType(int.class, int.class);
MethodType intfn2 = methodType(int.class, int.class, int.class);
MethodHandle sub = ... (int x, int y) -> (x-y) ...;
assert(sub.type().equals(intfn2));
MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
assert((int)rsub.invokeExact(1, 100) == 99);
MethodHandle add = ... (int x, int y) -> (x+y) ...;
assert(add.type().equals(intfn2));
MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
assert(twice.type().equals(intfn1));
assert((int)twice.invokeExact(21) == 42);

Примечание: полученный адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода был таким.

Параметры:
target — дескриптор метода, который нужно вызвать после перестановки аргументов
newType — ожидаемый тип нового дескриптора метода
reorder — массив индексов, задающий перестановку
Возвращает:
дескриптор метода, который делегирует вызов цели, отбросив неиспользуемые аргументы и переместив и/или продублировав остальные
Вызывает:
NullPointerException — если любой аргумент равен null
IllegalArgumentException — если длина массива индексов не равна арности цели, если какой-либо элемент массива индексов не является допустимым индексом параметра newType или если типы двух соответствующих параметров в target.type() и newType не совпадают,

constant

public static MethodHandle constant(Class<?> type, Object value)
Создаёт дескриптор метода с запрошенным возвращаемым типом, который при каждом вызове возвращает заданное постоянное значение.

Перед возвратом дескриптора метода переданное значение преобразуется к запрошенному типу. Если запрошенный тип — примитивный, выполняются попытки расширяющего преобразования примитивного типа; в противном случае выполняются попытки преобразования ссылочного типа.

Возвращаемый дескриптор метода эквивалентен identity(type).bindTo(value).

Параметры:
type — возвращаемый тип требуемого дескриптора метода
value — возвращаемое значение
Возвращает:
дескриптор метода заданного возвращаемого типа без аргументов, который всегда возвращает заданное значение
Вызывает:
NullPointerException — если аргумент type равен null
ClassCastException — если значение нельзя преобразовать к требуемому возвращаемому типу
IllegalArgumentException — если заданный тип является void.class

identity

public static MethodHandle identity(Class<?> type)
Создаёт дескриптор метода, который при вызове возвращает свой единственный аргумент.
Параметры:
type — тип единственного параметра и возвращаемого значения требуемого дескриптора метода
Возвращает:
унарный дескриптор метода, принимающий и возвращающий значение заданного типа
Вызывает:
NullPointerException — если аргумент равен null
IllegalArgumentException — если заданный тип является void.class

zero

public static MethodHandle zero(Class<?> type)
Создаёт константный дескриптор метода с запрошенным возвращаемым типом, который при каждом вызове возвращает значение по умолчанию для этого типа. Полученный константный дескриптор метода не будет иметь побочных эффектов.

Возвращаемый дескриптор метода эквивалентен empty(methodType(type)). Он также эквивалентен explicitCastArguments(constant(Object.class, null), methodType(type)), поскольку explicitCastArguments преобразует null в значения по умолчанию.

Параметры:
type — ожидаемый возвращаемый тип требуемого дескриптора метода
Возвращает:
константный дескриптор метода без аргументов, возвращающий значение по умолчанию для заданного типа (или void, если тип — void)
Вызывает:
NullPointerException — если аргумент равен null
С версии:
9
См. также:
  • constant(Class, Object)
  • empty(MethodType)
  • explicitCastArguments(MethodHandle, MethodType)

empty

public static MethodHandle empty(MethodType type)
Создаёт дескриптор метода запрошенного типа, который игнорирует любые аргументы, ничего не делает и возвращает подходящее значение по умолчанию в зависимости от возвращаемого типа. То есть он возвращает нулевое примитивное значение, null или void.

Возвращаемый дескриптор метода эквивалентен dropArguments(zero(type.returnType()), 0, type.parameterList()).

Примечание API:
Для заданного предиката и цели можно создать полезную конструкцию «если — то» следующим образом: guardWithTest(pred, target, empty(target.type()).
Параметры:
type — тип требуемого дескриптора метода
Возвращает:
константный дескриптор метода заданного типа, возвращающий значение по умолчанию для заданного возвращаемого типа
Вызывает:
NullPointerException — если аргумент равен null
С версии:
9
См. также:
  • zero(Class)
  • constant(Class, Object)

insertArguments

public static MethodHandle insertArguments(MethodHandle target, int pos, Object... values)
Предоставляет целевой дескриптор метода с одним или несколькими связанными аргументами, заданными до вызова дескриптора метода. Формальные параметры цели, соответствующие связанным аргументам, называются связанными параметрами. Возвращает новый дескриптор метода, сохраняющий связанные аргументы. При вызове он принимает аргументы для несвязанных параметров, привязывает сохранённые аргументы к соответствующим параметрам и вызывает исходную цель.

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

Каждый заданный объект-аргумент должен соответствовать типу связанного параметра. Если тип связанного параметра примитивный, объект-аргумент должен быть объектом-обёрткой; для получения примитивного значения он будет распакован.

Аргумент pos задаёт параметры для связывания. Его значение может находиться в диапазоне от нуля до N-L включительно, где N — арность целевого дескриптора метода, а L — длина массива значений.

Примечание: полученный адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода был таким.

Параметры:
target — дескриптор метода, который нужно вызвать после вставки аргумента
pos — место вставки аргумента (ноль означает первый аргумент)
values — последовательность вставляемых аргументов
Возвращает:
дескриптор метода, который вставляет дополнительный аргумент перед вызовом исходного дескриптора метода
Вызывает:
NullPointerException — если цель или массив values равны null
IllegalArgumentException — если pos меньше 0 или больше N - L, где N — арность целевого дескриптора метода, а L — длина массива значений.
ClassCastException — если аргумент не соответствует типу связанного параметра.
См. также:
  • MethodHandle.bindTo(Object)

dropArguments

public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)
Создаёт дескриптор метода, который отбрасывает фиктивные аргументы перед вызовом другого заданного целевого дескриптора метода. Тип нового дескриптора метода совпадает с типом цели, за исключением того, что в заданной позиции к нему добавляются типы фиктивных аргументов.

Аргумент pos может принимать значения от нуля до N, где N — арность цели. Если pos равен нулю, фиктивные аргументы предшествуют настоящим аргументам цели; если pos равен N, они следуют за ними.

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
  "concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
assertEquals(bigType, d0.type());
assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));

Этот метод также эквивалентен следующему коду:

 dropArguments(target, pos, valueTypes.toArray(new Class[0]))
 
Параметры:
target — дескриптор метода, который нужно вызвать после отбрасывания аргументов
pos — позиция первого отбрасываемого аргумента (ноль означает самый левый)
valueTypes — тип или типы отбрасываемых аргументов
Возвращает:
дескриптор метода, который отбрасывает аргументы заданных типов перед вызовом исходного дескриптора метода
Вызывает:
NullPointerException — если цель равна null, либо список valueTypes или любой его элемент равен null
IllegalArgumentException — если любой элемент valueTypes является void.class, если pos отрицателен или превышает арность цели либо если тип нового дескриптора метода будет содержать слишком много параметров

dropArguments

public static MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
Создает дескриптор метода, который отбрасывает некоторые фиктивные аргументы перед вызовом другого указанного дескриптора метода target. Тип нового дескриптора метода будет совпадать с типом целевого дескриптора, за исключением того, что он также будет включать типы фиктивных аргументов в заданной позиции.

Аргумент pos может принимать значения от нуля до N, где N — арность целевого дескриптора. Если pos равно нулю, фиктивные аргументы будут предшествовать реальным аргументам целевого дескриптора; если pos равно N, они будут следовать за ними.

Примечание API:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
  "concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle d0 = dropArguments(cat, 0, String.class);
assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
MethodHandle d1 = dropArguments(cat, 1, String.class);
assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
MethodHandle d2 = dropArguments(cat, 2, String.class);
assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));

Этот метод также эквивалентен следующему коду:

 dropArguments(target, pos, Arrays.asList(valueTypes))
 
Параметры:
target — дескриптор метода, вызываемый после отбрасывания аргументов
pos — позиция первого отбрасываемого аргумента (ноль для крайнего левого)
valueTypes — тип или типы отбрасываемых аргументов
Возвращает:
дескриптор метода, который отбрасывает аргументы заданных типов перед вызовом исходного дескриптора метода
Вызывает:
NullPointerException — если целевой дескриптор равен null либо массив valueTypes или любой из его элементов равен null
IllegalArgumentException — если любой элемент valueTypes равен void.class, если pos отрицательно или больше арности целевого дескриптора либо если тип нового дескриптора метода будет иметь слишком много параметров

dropArgumentsToMatch

public static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos)
Адаптирует целевой дескриптор метода, чтобы он соответствовал заданному списку типов параметров. При необходимости добавляются фиктивные аргументы. Перед началом сопоставления можно пропустить несколько начальных параметров. Оставшиеся типы в списке типов параметров target должны быть подсписком списка типов newTypes, начиная с позиции pos. Полученный дескриптор будет содержать список типов параметров целевого дескриптора, а все несовпадающие типы параметров (до или после совпадающего подсписка) будут вставлены в соответствующие позиции исходных параметров целевого дескриптора, как если бы был вызван dropArguments(MethodHandle, int, Class[]).

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

В более формальном изложении предположим, что имеются следующие два списка типов:

  • Целевой дескриптор содержит список типов параметров S..., M..., в котором число типов S задано значением skip. Типы M — это типы, которые должны совпасть с частью заданного списка типов newTypes.
  • Список newTypes содержит типы P..., M..., A..., в котором число типов P задано значением pos. Типы M — это именно те типы, с которыми должны совпасть типы M в списке типов параметров целевого дескриптора. Типы в A — это дополнительные типы после совпадающего подсписка.
При этих предположениях результат вызова dropArgumentsToMatch будет иметь список типов параметров S..., P..., M..., A..., причем типы P и A будут вставлены так, как если бы был вызван dropArguments(MethodHandle, int, Class[]).
Примечание API:
Два дескриптора метода, списки аргументов которых «эффективно идентичны» (то есть имеют общий идентичный префикс), можно взаимно преобразовать к общему типу двумя вызовами dropArgumentsToMatch следующим образом:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
...
MethodHandle h0 = constant(boolean.class, true);
MethodHandle h1 = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
MethodType bigType = h1.type().insertParameterTypes(1, String.class, int.class);
MethodHandle h2 = dropArguments(h1, 0, bigType.parameterList());
if (h1.type().parameterCount() < h2.type().parameterCount())
    h1 = dropArgumentsToMatch(h1, 0, h2.type().parameterList(), 0);  // lengthen h1
else
    h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0);    // lengthen h2
MethodHandle h3 = guardWithTest(h0, h1, h2);
assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
Параметры:
target — адаптируемый дескриптор метода
skip — число игнорируемых параметров целевого дескриптора (они останутся без изменений)
newTypes — список типов, которому должен соответствовать список типов параметров target
pos — позиция в newTypes, где должны находиться параметры целевого дескриптора, не подлежащие пропуску
Возвращает:
возможно, адаптированный дескриптор метода
Вызывает:
NullPointerException — если любой из аргументов равен null
IllegalArgumentException — если любой элемент newTypes равен void.class, если skip отрицательно или больше арности целевого дескриптора, если pos отрицательно или больше размера списка newTypes либо если newTypes не содержит пропускаемые параметры target в позиции pos.
Начиная с версии:
9

dropReturn

public static MethodHandle dropReturn(MethodHandle target)
Отбрасывает возвращаемое значение целевого дескриптора (если оно есть). Возвращаемый дескриптор метода будет иметь тип возвращаемого значения void.
Параметры:
target — адаптируемый дескриптор метода
Возвращает:
возможно, адаптированный дескриптор метода
Вызывает:
NullPointerException — если target равен null
Начиная с версии:
16

filterArguments

public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters)
Адаптирует целевой дескриптор метода, предварительно обрабатывая один или несколько его аргументов с помощью отдельных унарных функций-фильтров, а затем вызывая целевой дескриптор, заменив каждый предварительно обработанный аргумент результатом соответствующей функции-фильтра.

Предварительная обработка выполняется одним или несколькими дескрипторами методов, указанными в элементах массива filters. Первый элемент массива фильтров соответствует аргументу pos целевого дескриптора, следующий — следующему аргументу и так далее. Функции-фильтры вызываются слева направо.

Аргументы null в массиве рассматриваются как тождественные функции, а соответствующие аргументы остаются без изменений. (Если в массиве нет ненулевых элементов, возвращается исходный целевой дескриптор.) Каждый фильтр применяется к соответствующему аргументу адаптера.

Если фильтр F применяется к аргументу целевого дескриптора с номером N, то F должен быть дескриптором метода, принимающим ровно один аргумент. Тип единственного аргумента F заменяет соответствующий тип аргумента целевого дескриптора в результирующем адаптированном дескрипторе метода. Тип возвращаемого значения F должен совпадать с типом соответствующего параметра целевого дескриптора.

Наличие элементов filters (null или иных), не соответствующих позициям аргументов целевого дескриптора, является ошибкой.

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
  "concat", methodType(String.class, String.class));
MethodHandle upcase = lookup().findVirtual(String.class,
  "toUpperCase", methodType(String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle f0 = filterArguments(cat, 0, upcase);
assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
MethodHandle f1 = filterArguments(cat, 1, upcase);
assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY

Ниже приведен псевдокод результирующего адаптера. В коде T обозначает тип возвращаемого значения как target, так и результирующего адаптера. P/p и B/b обозначают типы и значения параметров и аргументов, предшествующих позиции фильтра pos и следующих за ней соответственно. A[i]/a[i] обозначают типы и значения фильтруемых параметров и аргументов; они также представляют типы возвращаемых значений дескрипторов filter[i]. Последние принимают аргументы v[i] типа V[i], которые также присутствуют в сигнатуре результирующего адаптера.

T target(P... p, A[i]... a[i], B... b);
A[i] filter[i](V[i]);
T adapter(P... p, V[i]... v[i], B... b) {
  return target(p..., filter[i](v[i])..., b...);
}

Примечание: Результирующий адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода им был.

Параметры:
target — дескриптор метода, вызываемый после фильтрации аргументов
pos — позиция первого фильтруемого аргумента
filters — дескрипторы методов, первоначально вызываемые для фильтруемых аргументов
Возвращает:
дескриптор метода, включающий указанную логику фильтрации аргументов
Вызывает:
NullPointerException — если целевой дескриптор равен null или массив filters равен null
IllegalArgumentException — если ненулевой элемент filters не соответствует типу соответствующего аргумента целевого дескриптора, как описано выше, если pos+filters.length больше target.type().parameterCount() либо если тип результирующего дескриптора метода будет иметь слишком много параметров

collectArguments

public static MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter)
Адаптирует целевой дескриптор метода, предварительно обрабатывая подпоследовательность его аргументов с помощью фильтра (другого дескриптора метода). Предварительно обработанные аргументы заменяются результатом функции-фильтра (если он есть). Затем целевой дескриптор вызывается с измененным (обычно сокращенным) списком аргументов.

Если фильтр возвращает значение, целевой дескриптор должен принимать это значение в качестве аргумента в позиции pos, перед которым и/или после которого могут находиться аргументы, не передаваемые фильтру. Если фильтр возвращает void, целевой дескриптор должен принимать все аргументы, не передаваемые фильтру. Аргументы не меняют порядок, а результат, возвращенный фильтром, заменяет (по порядку) всю подпоследовательность аргументов, изначально переданных адаптеру.

Типы аргументов фильтра (если они есть) заменяют в результирующем адаптированном дескрипторе метода ноль или один тип аргумента целевого дескриптора в позиции pos. Тип возвращаемого значения фильтра (если он есть) должен совпадать с типом аргумента целевого дескриптора в позиции pos, а этот аргумент целевого дескриптора получает значение, возвращенное фильтром.

Во всех случаях pos должно быть больше или равно нулю, а pos также должно быть меньше или равно арности целевого дескриптора.

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle deepToString = publicLookup()
  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));

MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
assertEquals("[strange]", (String) ts1.invokeExact("strange"));

MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));

MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
assertEquals("[top, [up, down], strange]",
             (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));

MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
assertEquals("[top, [up, down], [strange]]",
             (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));

MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
assertEquals("[top, [[up, down, strange], charm], bottom]",
             (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));

Ниже приведен псевдокод результирующего адаптера. В коде T обозначает тип возвращаемого значения target и результирующего адаптера. V/v обозначают тип и значение возвращаемого значения filter, которые также присутствуют соответственно в сигнатуре и аргументах target, если только V не равно void. A/a и C/c обозначают типы и значения параметров и аргументов, предшествующих позиции сбора pos в сигнатуре target и следующих за ней. Они также присутствуют в сигнатуре и аргументах результирующего адаптера, где окружают B/b, обозначающие типы параметров и аргументы filter (если они есть).

T target(A...,V,C...);
V filter(B...);
T adapter(A... a,B... b,C... c) {
  V v = filter(b...);
  return target(a...,v,c...);
}
// and if the filter has no arguments:
T target2(A...,V,C...);
V filter2();
T adapter2(A... a,C... c) {
  V v = filter2();
  return target2(a...,v,c...);
}
// and if the filter has a void return:
T target3(A...,C...);
void filter3(B...);
T adapter3(A... a,B... b,C... c) {
  filter3(b...);
  return target3(a...,c...);
}

Адаптер сбора collectArguments(mh, 0, coll) эквивалентен адаптеру, который сначала «сворачивает» затронутые аргументы, а затем отбрасывает их в два отдельных этапа следующим образом:

mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
mh = MethodHandles.foldArguments(mh, coll); //step 1
Если целевой дескриптор метода не принимает никаких аргументов, кроме результата (если он есть) фильтра coll, то collectArguments(mh, 0, coll) эквивалентен filterReturnValue(coll, mh). Если дескриптор метода фильтра coll принимает один аргумент и возвращает результат, отличный от void, то collectArguments(mh, N, coll) эквивалентен filterArguments(mh, N, coll). Возможны и другие эквивалентные варианты, но для них потребуется перестановка аргументов.

Примечание: Результирующий адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода им был.

Параметры:
target — дескриптор метода, вызываемый после фильтрации подпоследовательности аргументов
pos — позиция первого аргумента адаптера, передаваемого фильтру, и/или аргумента целевого дескриптора, получающего результат фильтра
filter — дескриптор метода, вызываемый для подпоследовательности аргументов
Возвращает:
дескриптор метода, включающий указанную логику фильтрации подпоследовательности аргументов
Вызывает:
NullPointerException — если любой из аргументов равен null
IllegalArgumentException — если тип возвращаемого значения filter отличен от void и не совпадает с типом аргумента pos целевого дескриптора, если pos не находится в диапазоне от 0 до арности целевого дескриптора включительно либо если тип результирующего дескриптора метода будет иметь слишком много параметров
См. также:
  • foldArguments(MethodHandle, MethodHandle)
  • filterArguments(MethodHandle, int, MethodHandle...)
  • filterReturnValue(MethodHandle, MethodHandle)

filterReturnValue

public static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter)
Адаптирует целевой дескриптор метода, обрабатывая его возвращаемое значение (если оно есть) с помощью фильтра (другого дескриптора метода). Результат фильтра возвращается адаптером.

Если целевой дескриптор возвращает значение, фильтр должен принимать это значение в качестве единственного аргумента. Если целевой дескриптор возвращает void, фильтр не должен принимать аргументов.

Тип возвращаемого значения фильтра заменяет тип возвращаемого значения целевого дескриптора в результирующем адаптированном дескрипторе метода. Тип аргумента фильтра (если он есть) должен совпадать с типом возвращаемого значения целевого дескриптора.

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
  "concat", methodType(String.class, String.class));
MethodHandle length = lookup().findVirtual(String.class,
  "length", methodType(int.class));
System.out.println((String) cat.invokeExact("x", "y")); // xy
MethodHandle f0 = filterReturnValue(cat, length);
System.out.println((int) f0.invokeExact("x", "y")); // 2

Ниже приведен псевдокод результирующего адаптера. В коде T/t обозначают тип и значение результата target; V — тип результата filter; а A/a — типы и значения параметров и аргументов target, а также результирующего адаптера.

T target(A...);
V filter(T);
V adapter(A... a) {
  T t = target(a...);
  return filter(t);
}
// and if the target has a void return:
void target2(A...);
V filter2();
V adapter2(A... a) {
  target2(a...);
  return filter2();
}
// and if the filter has a void return:
T target3(A...);
void filter3(V);
void adapter3(A... a) {
  T t = target3(a...);
  filter3(t);
}

Примечание: Результирующий адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода им был.

Параметры:
target — дескриптор метода, вызываемый перед фильтрацией возвращаемого значения
filter — дескриптор метода, вызываемый для возвращаемого значения
Возвращает:
дескриптор метода, включающий указанную логику фильтрации возвращаемого значения
Вызывает:
NullPointerException — если любой из аргументов равен null
IllegalArgumentException — если список аргументов filter не соответствует типу возвращаемого значения целевого дескриптора, как описано выше

foldArguments

public static MethodHandle foldArguments(MethodHandle target, MethodHandle combiner)
Адаптирует целевой дескриптор метода, предварительно обрабатывая некоторые его аргументы, а затем вызывая целевой дескриптор с результатом предварительной обработки, вставленным в исходную последовательность аргументов.

Предварительная обработка выполняется с помощью combiner — второго дескриптора метода. Первые N аргументов, переданных адаптеру, копируются в комбинирующий дескриптор, который затем вызывается. (Здесь N определяется как число параметров комбинирующего дескриптора.) После этого управление передается целевому дескриптору, причем результат комбинирующего дескриптора, если он есть, вставляется перед исходными входными аргументами N.

Если комбинирующий дескриптор возвращает значение, первый тип параметра целевого дескриптора должен совпадать с типом возвращаемого значения комбинирующего дескриптора, а следующие N типов параметров целевого дескриптора должны точно совпадать с параметрами комбинирующего дескриптора.

Если комбинирующий дескриптор возвращает void, результат не вставляется, а первые N типов параметров целевого дескриптора должны точно совпадать с параметрами комбинирующего дескриптора.

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

(Обратите внимание, что dropArguments можно использовать для удаления любых аргументов, которые не требуется получать комбинирующему или целевому дескриптору. Если некоторые входные аргументы предназначены только для комбинирующего дескриптора, рассмотрите возможность использования asCollector, поскольку в этом случае эти аргументы не потребуется сохранять в стеке при входе в целевой дескриптор.)

Пример:

import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
  "println", methodType(void.class, String.class))
    .bindTo(System.out);
MethodHandle cat = lookup().findVirtual(String.class,
  "concat", methodType(String.class, String.class));
assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
MethodHandle catTrace = foldArguments(cat, trace);
// also prints "boo":
assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));

Ниже приведен псевдокод результирующего адаптера. В коде T обозначает тип результата target и результирующего адаптера. V/v обозначают тип и значение параметра и аргумента target, предшествующих позиции свертки; V также является типом результата combiner. A/a обозначают типы и значения параметров и аргументов N в позиции свертки. B/b обозначают типы и значения параметров и аргументов target, следующих за свернутыми параметрами и аргументами.

// there are N arguments in A...
T target(V, A[N]..., B...);
V combiner(A...);
T adapter(A... a, B... b) {
  V v = combiner(a...);
  return target(v, a..., b...);
}
// and if the combiner has a void return:
T target2(A[N]..., B...);
void combiner2(A...);
T adapter2(A... a, B... b) {
  combiner2(a...);
  return target2(a..., b...);
}

Примечание: Результирующий адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода им был.

Параметры:
target — дескриптор метода, вызываемый после объединения аргументов
combiner — дескриптор метода, первоначально вызываемый для входных аргументов
Возвращает:
дескриптор метода, включающий указанную логику свертки аргументов
Вызывает:
NullPointerException — если любой из аргументов равен null
IllegalArgumentException — если тип возвращаемого значения combiner отличен от void и не совпадает с типом первого аргумента целевого дескриптора либо если начальные N типов аргументов целевого дескриптора (за исключением одного, совпадающего с типом возвращаемого значения combiner) не совпадают с типами аргументов combiner

foldArguments

public static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner)
Адаптирует целевой дескриптор метода, предварительно обрабатывая некоторые его аргументы, начиная с заданной позиции, а затем вызывая целевой дескриптор с результатом предварительной обработки, вставленным в исходную последовательность аргументов непосредственно перед свернутыми аргументами.

Этот метод тесно связан с foldArguments(MethodHandle, MethodHandle), но позволяет управлять позицией в списке параметров, в которой выполняется свертка. Аргумент, задающий эту позицию, pos, является индексом, начинающимся с нуля. Упомянутый выше метод foldArguments(MethodHandle, MethodHandle) предполагает позицию 0.

Примечание API:
Пример:
   import static java.lang.invoke.MethodHandles.*;
   import static java.lang.invoke.MethodType.*;
   ...
   MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
   "println", methodType(void.class, String.class))
   .bindTo(System.out);
   MethodHandle cat = lookup().findVirtual(String.class,
   "concat", methodType(String.class, String.class));
   assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
   MethodHandle catTrace = foldArguments(cat, 1, trace);
   // also prints "jum":
   assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));

Ниже приведен псевдокод результирующего адаптера. В коде T обозначает тип результата target и результирующего адаптера. V/v обозначают тип и значение параметра и аргумента target, предшествующих позиции свертки; V также является типом результата combiner. A/a обозначают типы и значения параметров и аргументов N в позиции свертки. Z/z и B/b обозначают типы и значения параметров и аргументов target, предшествующих и следующих за свернутыми параметрами и аргументами, начинающимися с pos, соответственно.

// there are N arguments in A...
T target(Z..., V, A[N]..., B...);
V combiner(A...);
T adapter(Z... z, A... a, B... b) {
  V v = combiner(a...);
  return target(z..., v, a..., b...);
}
// and if the combiner has a void return:
T target2(Z..., A[N]..., B...);
void combiner2(A...);
T adapter2(Z... z, A... a, B... b) {
  combiner2(a...);
  return target2(z..., a..., b...);
}

Примечание: Результирующий адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода им был.

Параметры:
target — дескриптор метода, вызываемый после объединения аргументов
pos — позиция, с которой начинается свертка и в которую вставляется результат свертки; если это значение равно 0, эффект будет таким же, как у foldArguments(MethodHandle, MethodHandle).
combiner — дескриптор метода, первоначально вызываемый для входных аргументов
Возвращает:
дескриптор метода, включающий указанную логику свертки аргументов
Вызывает:
NullPointerException — если любой из аргументов равен null
IllegalArgumentException — если выполняется любое из следующих двух условий: (1) тип возвращаемого значения combiner отличен от void и не совпадает с типом аргумента в позиции pos сигнатуры целевого дескриптора; (2) типы N аргументов в позиции pos сигнатуры целевого дескриптора (за исключением одного, совпадающего с типом возвращаемого значения combiner) не совпадают с типами аргументов combiner.
Начиная с версии:
9
См. также:
  • foldArguments(MethodHandle, MethodHandle)

guardWithTest

public static MethodHandle guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)
Создает дескриптор метода, адаптирующий целевой дескриптор с помощью проверки — дескриптора метода, возвращающего логическое значение. Если проверка не пройдена, вместо него вызывается резервный дескриптор. Все три дескриптора метода должны иметь одинаковые соответствующие типы аргументов и возвращаемых значений, за исключением того, что проверка должна возвращать boolean и может принимать меньше аргументов, чем два других дескриптора.

Ниже приведен псевдокод результирующего адаптера. В коде T обозначает общий тип результата трех задействованных дескрипторов; A/a — типы и значения параметров и аргументов target, используемых test; а B/b — типы и значения параметров и аргументов target, не используемых test.

boolean test(A...);
T target(A...,B...);
T fallback(A...,B...);
T adapter(A... a,B... b) {
  if (test(a...))
    return target(a..., b...);
  else
    return fallback(a..., b...);
}
Обратите внимание, что аргументы проверки (a... в псевдокоде) не могут быть изменены при выполнении проверки и поэтому передаются от вызывающего к целевому или резервному дескриптору без изменений, в зависимости от ситуации.
Параметры:
test — дескриптор метода для проверки, должен возвращать boolean
target — дескриптор метода, вызываемый, если проверка пройдена
fallback — дескриптор метода, вызываемый, если проверка не пройдена
Возвращает:
дескриптор метода, включающий указанную логику if/then/else
Вызывает:
NullPointerException — если любой аргумент равен null
IllegalArgumentException — если test не возвращает boolean либо если типы всех трех дескрипторов методов не совпадают (с изменением типа возвращаемого значения test на соответствующий тип целевого дескриптора).

catchException

public static MethodHandle catchException(MethodHandle target, Class<? extends Throwable> exType, MethodHandle handler)
Создает дескриптор метода, адаптирующий целевой дескриптор путем выполнения его внутри обработчика исключений. Если целевой дескриптор завершается нормально, адаптер возвращает это значение. Если возникает исключение указанного типа, вместо него для исключения и исходных аргументов вызывается резервный дескриптор.

Целевой дескриптор и обработчик должны иметь одинаковые соответствующие типы аргументов и возвращаемых значений, за исключением того, что обработчик может не принимать конечные аргументы (подобно предикату в guardWithTest). Кроме того, обработчик должен иметь дополнительный начальный параметр типа exType или его суперкласса.

Ниже приведен псевдокод результирующего адаптера. В коде T обозначает тип возвращаемого значения target и handler, а также результирующего адаптера; A/a — типы и значения аргументов результирующего дескриптора, используемых handler; а B/b — типы и значения аргументов результирующего дескриптора, отбрасываемых handler.

T target(A..., B...);
T handler(ExType, A...);
T adapter(A... a, B... b) {
  try {
    return target(a..., b...);
  } catch (ExType ex) {
    return handler(ex, a...);
  }
}
Обратите внимание, что сохраненные аргументы (a... в псевдокоде) не могут быть изменены при выполнении целевого дескриптора и поэтому передаются от вызывающего обработчику без изменений, если обработчик вызывается.

Целевой дескриптор и обработчик должны возвращать один и тот же тип, даже если обработчик всегда генерирует исключение. (Так может происходить, например, если обработчик имитирует блок finally.) Чтобы создать такой обработчик, генерирующий исключение, объедините логику его создания с throwException, чтобы создать дескриптор метода с правильным типом возвращаемого значения.

Параметры:
target — вызываемый дескриптор метода
exType — тип исключения, перехватываемого обработчиком
handler — дескриптор метода, вызываемый при возникновении соответствующего исключения
Возвращает:
дескриптор метода, включающий указанную логику try/catch
Вызывает:
NullPointerException — если любой аргумент равен null
IllegalArgumentException — если handler не принимает заданный тип исключения либо если типы дескрипторов методов не совпадают по типам возвращаемых значений и соответствующим параметрам
См. также:
  • tryFinally(MethodHandle, MethodHandle)

throwException

public static MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType)
Создает дескриптор метода, который будет генерировать исключения заданного типа exType. Дескриптор метода принимает один аргумент типа exType и немедленно генерирует его как исключение. В сигнатуре типа метода формально указывается возвращаемое значение типа returnType. Тип возвращаемого значения может быть любым подходящим: он не влияет на поведение дескриптора метода, поскольку тот никогда не завершится обычным возвратом.
Параметры:
returnType — тип возвращаемого значения требуемого дескриптора метода
exType — тип параметра требуемого дескриптора метода
Возвращает:
дескриптор метода, способный генерировать заданные исключения
Вызывает:
NullPointerException — если любой из аргументов равен null

loop

public static MethodHandle loop(MethodHandle[]... clauses)
Создает дескриптор метода, представляющий цикл с несколькими переменными цикла, которые обновляются и проверяются при каждой итерации. При завершении цикла из-за одного из предикатов выполняется соответствующая завершающая функция и возвращает результат цикла — возвращаемое значение результирующего дескриптора.

Интуитивно каждый цикл образован одной или несколькими «частями», каждая из которых задает локальную переменную итерации и/или условие выхода из цикла. При каждой итерации цикла выполняется каждая часть по порядку. Часть может обновлять свою переменную итерации; кроме того, она может выполнять проверку и условный выход из цикла. Чтобы выразить эту логику в терминах дескрипторов методов, каждая часть задает до четырех независимых действий:

  • init: инициализация переменной итерации v типа V перед выполнением цикла.
  • step: при выполнении части — шаг обновления переменной итерации v.
  • pred: при выполнении части — вычисление предиката для проверки выхода из цикла.
  • fini: если часть приводит к выходу из цикла — выполнение завершающей функции для вычисления возвращаемого значения цикла.
Полная последовательность типов всех переменных итерации в порядке частей обозначается как (V...). Сами значения обозначаются как (v...). Говоря о «списках параметров», мы обычно имеем в виду типы, однако в некоторых контекстах (при описании выполнения) списки будут содержать фактические значения.

Некоторые части могут быть опущены в соответствии с определенными правилами; в этом случае предусмотрено полезное поведение по умолчанию. Подробное описание приведено ниже.

Параметры необязательны во всех случаях: Каждая функция части может принимать параметр для каждой переменной итерации v, но это не обязательно. Исключение составляют функции init: они не могут принимать параметры v, поскольку эти значения еще не вычислены при выполнении функций init. Любая функция части может не принимать любой конечный подпоследовательный набор параметров, которые она вправе принимать. Фактически любая функция части может вообще не принимать аргументов.

Параметры цикла: Функция части может принимать все значения переменных итерации, которые она вправе принимать, а также дополнительные конечные параметры. Такие дополнительные значения называются параметрами цикла; их типы и значения обозначаются как (A...) и (a...). Они становятся параметрами результирующего дескриптора цикла и передаются при каждом выполнении цикла. (Поскольку функции init не принимают переменные итерации v, любой параметр функции init автоматически является параметром цикла a.) Как и в случае с переменными итерации, функции частей могут принимать параметры цикла, но это не обязательно. Эти параметры цикла являются инвариантными значениями, доступными во всем цикле.

Параметры, доступные повсюду: Каждая функция части, кроме init, может наблюдать все состояние цикла, поскольку ей можно передать полный список (v... a...) текущих значений переменных итерации и входных параметров цикла. Функции init могут наблюдать начальное состояние до цикла в виде (a...). Большинству функций частей не понадобятся все эти сведения, но формально они будут связаны с ними так, как если бы к ним применили dropArguments(MethodHandle, int, List). В частности, обозначением (V*) мы будем выражать произвольный префикс полной последовательности (V...) (и аналогично для (v*), (A*), (a*)). В этих обозначениях общий вид списка параметров функции init — (A*), а общий вид списка параметров функции, отличной от init, — (V*) или (V... A*).

Проверка структуры частей: Для соединения всех частей цикла при заданном наборе частей выполняется ряд проверок и корректировок. Они подробно описаны в следующих шагах. В этих шагах каждое употребление слова «должен» соответствует месту, где будет выброшено исключение IllegalArgumentException, если входные данные комбинатора цикла не удовлетворяют требуемому ограничению.

Эффективно идентичные последовательности: Список параметров A считается эффективно идентичным другому списку параметров B, если A и B идентичны либо если A короче и совпадает с собственным префиксом B. Говоря о неупорядоченном наборе списков параметров, мы считаем, что весь набор «эффективно идентичен», если он содержит самый длинный список и все его элементы эффективно идентичны этому самому длинному списку. Например, любой набор последовательностей типов вида (V*) эффективно идентичен; то же верно, если добавить больше последовательностей вида (V... A*).

Шаг 0: определить структуру частей.

  1. Массив частей (типа MethodHandle[][]) не должен быть null и должен содержать как минимум один элемент.
  2. Массив частей не может содержать значения null или подмассивы длиной больше четырех элементов.
  3. Считается, что части длиной меньше четырех элементов дополнены значениями null до длины четыре. Дополнение выполняется добавлением элементов в конец массива.
  4. Части, состоящие только из значений null, игнорируются.
  5. Каждая часть рассматривается как кортеж из четырех функций, называемых «init», «step», «pred» и «fini».

Шаг 1A: определить типы переменных итерации (V...).

  1. Тип переменной итерации для каждой части определяется типами возвращаемых значений функций init и step этой части.
  2. Если обе функции опущены, у соответствующей части нет переменной итерации (в качестве типа для обозначения этого используется void). Если одна из функций опущена, тип возвращаемого значения другой функции определяет тип переменной итерации этой части. Если заданы обе функции, общий тип возвращаемого значения (они должны быть идентичны) определяет тип переменной итерации этой части.
  3. Сформировать список типов возвращаемых значений (в порядке частей), исключив все вхождения void.
  4. Этот список типов называется «типами переменных итерации» ((V...)).

Шаг 1B: определить параметры цикла (A...).

  • Проверить и собрать списки параметров функций init (имеющие вид (A*)).
  • Проверить и собрать суффиксы списков параметров функций step, pred и fini после удаления типов переменных итерации. (Они должны иметь вид (V... A*); следует собирать только части (A*).)
  • Не собирать суффиксы списков параметров функций step, pred и fini, если они не начинаются со всех типов переменных итерации. (Эти типы будут проверены на шаге 2 вместе со всеми типами функций частей.)
  • Опущенные функции частей игнорируются. (Иными словами, считается, что их списки параметров пусты.)
  • Все собранные списки параметров должны быть эффективно идентичны.
  • Самый длинный список параметров (который обязательно единственный) называется «внешним списком параметров» ((A...)).
  • Если такого списка параметров нет, внешний список параметров считается пустой последовательностью.
  • Объединенный список, состоящий из типов переменных итерации, за которыми следуют типы внешних параметров, называется «внутренним списком параметров».

Шаг 1C: определить тип возвращаемого значения цикла.

  1. Проверить типы возвращаемых значений функций fini, не учитывая опущенные функции fini.
  2. Если функций fini нет, тип возвращаемого значения цикла — void.
  3. В противном случае общий тип возвращаемого значения R функций fini (типы их возвращаемых значений должны быть идентичны) определяет тип возвращаемого значения цикла.

Шаг 1D: проверить остальные типы.

  1. Должна быть задана как минимум одна функция pred.
  2. Тип возвращаемого значения каждой заданной функции pred должен быть boolean.

Шаг 2: определить списки параметров.

  1. Список параметров результирующего дескриптора цикла будет совпадать с внешним списком параметров (A...).
  2. Список параметров функций init будет скорректирован в соответствии с внешним списком параметров. (Обратите внимание, что их списки параметров уже эффективно идентичны этому списку.)
  3. Список параметров каждой заданной функции, отличной от init (step, pred и fini), должен быть эффективно идентичен внутреннему списку параметров (V... A...).

Шаг 3: заполнить опущенные функции.

  1. Если функция init опущена, использовать значение по умолчанию для типа переменной итерации этой части.
  2. Если функция step опущена, использовать тождественную функцию типа переменной итерации этой части; перед параметром тождественной функции добавить отброшенные параметры для переменных итерации, отличных от void, в предшествующих частях. (Это превратит переменную цикла в локальный инвариант цикла.)
  3. Если функция pred опущена, использовать константную функцию true. (С точки зрения этой части цикл продолжит выполняться. Обратите внимание, что в таких случаях соответствующая функция fini недостижима.)
  4. Если функция fini опущена, использовать значение по умолчанию для типа возвращаемого значения цикла.

Шаг 4: заполнить отсутствующие типы параметров.

  1. На этом этапе список параметров каждой функции init эффективно идентичен внешнему списку параметров (A...), но некоторые списки могут быть короче. Дополнить конец списка каждой функции init с коротким списком параметров.
  2. На этом этапе список параметров каждой функции, отличной от init, эффективно идентичен внутреннему списку параметров (V... A...), но некоторые списки могут быть короче. Дополнить конец списка каждой функции, отличной от init, с коротким списком параметров.
  3. Списки аргументов дополняются путем отбрасывания неиспользуемых конечных аргументов.

Заключительные замечания.

  1. После выполнения этих шагов все части скорректированы путем добавления опущенных функций и аргументов.
  2. Все функции init имеют общий список типов параметров (A...), который будет и у итогового дескриптора цикла.
  3. Все функции fini имеют общий тип возвращаемого значения R, который будет и у итогового дескриптора цикла.
  4. Все функции, кроме init, имеют общий список типов параметров (V... A...), состоящий из переменных итерации (не-void) V, за которыми следуют параметры цикла.
  5. Типы возвращаемых значений каждой пары функций init и step совпадают: V.
  6. Каждая функция, кроме init, может наблюдать текущие значения (v...) всех переменных итерации.
  7. Каждая функция может наблюдать входные значения (a...) всех параметров цикла.

Пример. Как следует из шага 1A выше, комбинатор loop обладает следующим свойством:

  • Заданы N частей Cn = {null, Sn, Pn} с n = 1..N.
  • Предположим, что дескрипторы предикатов Pn либо являются null, либо не имеют параметров. (Только один Pn должен быть не-null.)
  • Предположим, что дескрипторы шагов Sn имеют сигнатуры (B1..BX)Rn для некоторого постоянного X>=N.
  • Пусть Q — количество типов, отличных от void, Rn, а (V1...VQ) — последовательность этих типов.
  • Должно выполняться Vn == Bn для n = 1..min(X,Q).
  • Типы параметров Vn будут интерпретироваться как локальные для цикла элементы состояния (V...).
  • Все оставшиеся типы BQ+1..BX (если Q<X) определяют типы параметров результирующего дескриптора цикла (A...).
В этом примере параметры дескриптора цикла (A...) получены из функций step, что естественно, если основная часть вычислений цикла выполняется в шагах. В некоторых циклах основная вычислительная нагрузка может приходиться на функции pred, и тогда этим функциям может потребоваться принимать значения параметров цикла. В циклах со сложной логикой выхода функции fini могут принимать параметры цикла; аналогично, в циклах со сложной логикой входа дополнительные параметры понадобятся функциям init. Поэтому правила определения этих параметров по возможности симметричны для всех частей цикла. В общем случае параметры цикла служат общими инвариантными значениями для всего цикла, а переменные итерации — общими изменяемыми значениями или (если функция step отсутствует) временными внутренними инвариантами цикла.

Выполнение цикла.

  1. При вызове цикла входные значения цикла сохраняются в локальных переменных, чтобы передавать их каждой функции части. Эти локальные переменные инвариантны в цикле.
  2. Каждая функция init выполняется в порядке частей (с передачей внешних аргументов (a...)), а значения, отличные от void, сохраняются в локальных переменных как переменные итерации (v...). Эти локальные переменные будут изменяться в цикле (если только соответствующие функции step не ведут себя как тождественные функции, как отмечено выше).
  3. Всем функциям, кроме init, передается внутренний список параметров, состоящий из значений переменных итерации, отличных от void, (v...) (в порядке частей), а затем входных данных цикла (a...) (в порядке аргументов).
  4. Затем функции step и pred выполняются в порядке частей (сначала step, затем pred), пока функция pred не вернет false.
  5. Результат, отличный от void, вызова функции step используется для обновления соответствующего значения в последовательности (v...) переменных цикла. Обновленное значение сразу становится доступным всем последующим вызовам функций.
  6. Если функция pred возвращает false, вызывается соответствующая функция fini, а полученное значение типа R возвращается как результат всего цикла.
  7. Если все функции pred всегда возвращают true, функции fini никогда не вызываются, и цикл может завершиться только путем выбрасывания исключения.

Советы по использованию.

  • Хотя каждая функция step получает текущие значения всех переменных цикла, иногда ей требуется наблюдать только текущее значение собственной переменной. В таком случае функции step может потребоваться явно отбросить все предшествующие переменные цикла. Для этого нужно указать их типы, например в выражении dropArguments(step, 0, V0.class, ...).
  • Переменные цикла не обязательно должны изменяться: они могут быть инвариантами цикла. Часть может создать инвариант цикла с помощью подходящей функции init без функций step, pred или fini. Это может пригодиться, чтобы «подключить» входной аргумент цикла к функции step или pred соседней переменной цикла.
  • Если некоторые функции частей являются виртуальными методами экземпляра, сам экземпляр удобно поместить в начальную инвариантную «переменную» цикла, используя начальную часть вроде new MethodHandle[]{identity(ObjType.class)}. В этом случае ссылка на экземпляр будет первым значением переменной итерации, и виртуальные методы будет удобно использовать в качестве частей, поскольку все они будут принимать начальную ссылку на экземпляр, соответствующую этому значению.
Ниже приведен псевдокод результирующего дескриптора цикла. Как и выше, V и v обозначают типы и значения переменных цикла; A и a обозначают аргументы, передаваемые всему циклу; а R — общий тип результата всех завершающих функций, а также результирующего цикла.
V... init...(A...);
boolean pred...(V..., A...);
V... step...(V..., A...);
R fini...(V..., A...);
R loop(A... a) {
  V... v... = init...(a...);
  for (;;) {
    for ((v, p, s, f) in (v..., pred..., step..., fini...)) {
      v = s(v..., a...);
      if (!p(v..., a...)) {
        return f(v..., a...);
      }
    }
  }
}
Обратите внимание, что списки типов параметров (V...) и (A...) развернуты до полной длины, хотя отдельные функции частей могут не принимать их целиком. Как отмечено выше, недостающие параметры заполняются так, как если бы применялся dropArgumentsToMatch(MethodHandle, int, List, int).
Примечание API:
Пример:
// iterative implementation of the factorial function as a loop handle
static int one(int k) { return 1; }
static int inc(int i, int acc, int k) { return i + 1; }
static int mult(int i, int acc, int k) { return i * acc; }
static boolean pred(int i, int acc, int k) { return i < k; }
static int fin(int i, int acc, int k) { return acc; }
// assume MH_one, MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
// null initializer for counter, should initialize to 0
MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
assertEquals(120, loop.invoke(5));
Тот же пример с отбрасыванием аргументов и использованием комбинаторов:
// simplified implementation of the factorial function as a loop handle
static int inc(int i) { return i + 1; } // drop acc, k
static int mult(int i, int acc) { return i * acc; } //drop k
static boolean cmp(int i, int k) { return i < k; }
// assume MH_inc, MH_mult, and MH_cmp are handles to the above methods
// null initializer for counter, should initialize to 0
MethodHandle MH_one = MethodHandles.constant(int.class, 1);
MethodHandle MH_pred = MethodHandles.dropArguments(MH_cmp, 1, int.class); // drop acc
MethodHandle MH_fin = MethodHandles.dropArguments(MethodHandles.identity(int.class), 0, int.class); // drop i
MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
assertEquals(720, loop.invoke(6));
Похожий пример, в котором для хранения параметра цикла используется вспомогательный объект:
// instance-based implementation of the factorial function as a loop handle
static class FacLoop {
  final int k;
  FacLoop(int k) { this.k = k; }
  int inc(int i) { return i + 1; }
  int mult(int i, int acc) { return i * acc; }
  boolean pred(int i) { return i < k; }
  int fin(int i, int acc) { return acc; }
}
// assume MH_FacLoop is a handle to the constructor
// assume MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
// null initializer for counter, should initialize to 0
MethodHandle MH_one = MethodHandles.constant(int.class, 1);
MethodHandle[] instanceClause = new MethodHandle[]{MH_FacLoop};
MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
MethodHandle loop = MethodHandles.loop(instanceClause, counterClause, accumulatorClause);
assertEquals(5040, loop.invoke(7));
Параметры:
clauses — массив массивов (кортежей из четырех элементов) с элементами типа MethodHandle, удовлетворяющими описанным выше правилам.
Возвращает:
дескриптор метода, реализующий поведение цикла, определенное аргументами.
Исключения:
IllegalArgumentException — если нарушено какое-либо из описанных выше ограничений.
Начиная с версии:
9
См. также:
  • whileLoop(MethodHandle, MethodHandle, MethodHandle)
  • doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
  • countedLoop(MethodHandle, MethodHandle, MethodHandle)
  • iteratedLoop(MethodHandle, MethodHandle, MethodHandle)

whileLoop

public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body)
Создает цикл while на основе инициализатора, тела и предиката. Это вспомогательная обертка для универсального комбинатора цикла.

Дескриптор pred задает условие цикла, а body — его тело. В каждой итерации цикла, создаваемого этим методом, сначала вычисляется предикат, а затем выполняется тело (если предикат принимает значение true). Цикл завершается, как только предикат принимает значение false (в этом случае тело не выполняется).

Дескриптор init задает начальное значение дополнительной необязательной локальной переменной цикла. В каждой итерации, если эта локальная переменная цикла существует, она передается в body и обновляется значением, возвращенным при вызове этого дескриптора. Результатом выполнения цикла будет итоговое значение дополнительной локальной переменной цикла (если она существует).

Для этих дескрипторов-аргументов действуют следующие правила:

  • Дескриптор body не должен быть null; его тип должен иметь вид (V A...)V, где V не является void, либо быть (A...)void. (В случае void тип void присваивается имени V, и обозначение (V A...)V используется с учетом того, что тип void V незаметно удаляется из списка параметров, оставляя (A...)V.)
  • Список параметров (V A...) тела называется внутренним списком параметров. Он ограничивает списки параметров остальных частей цикла.
  • Если удалить тип переменной итерации V из внутреннего списка параметров, получившийся более короткий список (A...) называется внешним списком параметров.
  • Тип возвращаемого значения тела V, если он не void, определяет тип дополнительной переменной состояния цикла. Тело должно как принимать, так и возвращать значение этого типа V.
  • Если init не является null, он должен иметь тип возвращаемого значения V. Его список параметров (некоторой формы (A*)) должен быть эффективно идентичен внешнему списку параметров (A...).
  • Если init — это null, переменной цикла присваивается ее значение по умолчанию.
  • Дескриптор pred не должен быть null. Он должен иметь boolean в качестве типа возвращаемого значения. Его список параметров (пустой или имеющий вид (V A*)) должен быть эффективно идентичен внутреннему списку параметров.

Тип возвращаемого значения и сигнатура параметров результирующего дескриптора цикла определяются следующим образом:

  • Тип возвращаемого значения дескриптора цикла — тип результата V тела.
  • Типы параметров дескриптора цикла — типы (A...) из внешнего списка параметров.

Ниже приведен псевдокод результирующего дескриптора цикла. В коде V/v обозначают тип/значение единственной переменной цикла, а также тип результата цикла; A/a обозначают тип/значение аргумента, передаваемого циклу.

V init(A...);
boolean pred(V, A...);
V body(V, A...);
V whileLoop(A... a...) {
  V v = init(a...);
  while (pred(v, a...)) {
    v = body(v, a...);
  }
  return v;
}
Примечание API:
Пример:
// implement the zip function for lists as a loop handle
static List<String> initZip(Iterator<String> a, Iterator<String> b) { return new ArrayList<>(); }
static boolean zipPred(List<String> zip, Iterator<String> a, Iterator<String> b) { return a.hasNext() && b.hasNext(); }
static List<String> zipStep(List<String> zip, Iterator<String> a, Iterator<String> b) {
  zip.add(a.next());
  zip.add(b.next());
  return zip;
}
// assume MH_initZip, MH_zipPred, and MH_zipStep are handles to the above methods
MethodHandle loop = MethodHandles.whileLoop(MH_initZip, MH_zipPred, MH_zipStep);
List<String> a = Arrays.asList("a", "b", "c", "d");
List<String> b = Arrays.asList("e", "f", "g", "h");
List<String> zipped = Arrays.asList("a", "e", "b", "f", "c", "g", "d", "h");
assertEquals(zipped, (List<String>) loop.invoke(a.iterator(), b.iterator()));
Реализацию этого метода можно выразить следующим образом:
MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
    MethodHandle fini = (body.type().returnType() == void.class
                        ? null : identity(body.type().returnType()));
    MethodHandle[]
        checkExit = { null, null, pred, fini },
        varBody   = { init, body };
    return loop(checkExit, varBody);
}
Параметры:
init — необязательный инициализатор, задающий начальное значение переменной цикла. Может быть null, что означает использование начального значения по умолчанию. Другие ограничения см. выше.
pred — условие цикла, которое не может быть null. Тип результата должен быть boolean. Другие ограничения см. выше.
body — тело цикла, которое не может быть null. Оно определяет параметры цикла и тип возвращаемого значения. Другие ограничения см. выше.
Возвращает:
дескриптор метода, реализующий цикл while, описанный аргументами.
Исключения:
IllegalArgumentException — если нарушены правила для аргументов.
NullPointerException — если pred или body являются null.
Начиная с версии:
9
См. также:
  • loop(MethodHandle[][])
  • doWhileLoop(MethodHandle, MethodHandle, MethodHandle)

doWhileLoop

public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred)
Создает цикл do-while на основе инициализатора, тела и предиката. Это вспомогательная обертка для универсального комбинатора цикла.

Дескриптор pred задает условие цикла, а body — его тело. В каждой итерации цикла, создаваемого этим методом, сначала выполняется тело, а затем вычисляется предикат. Цикл завершается, как только после выполнения тела предикат принимает значение false.

Дескриптор init задает начальное значение дополнительной необязательной локальной переменной цикла. В каждой итерации, если эта локальная переменная цикла существует, она передается в body и обновляется значением, возвращенным при вызове этого дескриптора. Результатом выполнения цикла будет итоговое значение дополнительной локальной переменной цикла (если она существует).

Для этих дескрипторов-аргументов действуют следующие правила:

  • Дескриптор body не должен быть null; его тип должен иметь вид (V A...)V, где V не является void, либо быть (A...)void. (В случае void тип void присваивается имени V, и обозначение (V A...)V используется с учетом того, что тип void V незаметно удаляется из списка параметров, оставляя (A...)V.)
  • Список параметров (V A...) тела называется внутренним списком параметров. Он ограничивает списки параметров остальных частей цикла.
  • Если удалить тип переменной итерации V из внутреннего списка параметров, получившийся более короткий список (A...) называется внешним списком параметров.
  • Тип возвращаемого значения тела V, если он не void, определяет тип дополнительной переменной состояния цикла. Тело должно как принимать, так и возвращать значение этого типа V.
  • Если init не является null, он должен иметь тип возвращаемого значения V. Его список параметров (некоторой формы (A*)) должен быть эффективно идентичен внешнему списку параметров (A...).
  • Если init — это null, переменной цикла присваивается ее значение по умолчанию.
  • Дескриптор pred не должен быть null. Он должен иметь boolean в качестве типа возвращаемого значения. Его список параметров (пустой или имеющий вид (V A*)) должен быть эффективно идентичен внутреннему списку параметров.

Тип возвращаемого значения и сигнатура параметров результирующего дескриптора цикла определяются следующим образом:

  • Тип возвращаемого значения дескриптора цикла — тип результата V тела.
  • Типы параметров дескриптора цикла — типы (A...) из внешнего списка параметров.

Ниже приведен псевдокод результирующего дескриптора цикла. В коде V/v обозначают тип/значение единственной переменной цикла, а также тип результата цикла; A/a обозначают тип/значение аргумента, передаваемого циклу.

V init(A...);
boolean pred(V, A...);
V body(V, A...);
V doWhileLoop(A... a...) {
  V v = init(a...);
  do {
    v = body(v, a...);
  } while (pred(v, a...));
  return v;
}
Примечание API:
Пример:
// int i = 0; while (i < limit) { ++i; } return i; => limit
static int zero(int limit) { return 0; }
static int step(int i, int limit) { return i + 1; }
static boolean pred(int i, int limit) { return i < limit; }
// assume MH_zero, MH_step, and MH_pred are handles to the above methods
MethodHandle loop = MethodHandles.doWhileLoop(MH_zero, MH_step, MH_pred);
assertEquals(23, loop.invoke(23));
Реализацию этого метода можно выразить следующим образом:
MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
    MethodHandle fini = (body.type().returnType() == void.class
                        ? null : identity(body.type().returnType()));
    MethodHandle[] clause = { init, body, pred, fini };
    return loop(clause);
}
Параметры:
init — необязательный инициализатор, задающий начальное значение переменной цикла. Может быть null, что означает использование начального значения по умолчанию. Другие ограничения см. выше.
body — тело цикла, которое не может быть null. Оно определяет параметры цикла и тип возвращаемого значения. Другие ограничения см. выше.
pred — условие цикла, которое не может быть null. Тип результата должен быть boolean. Другие ограничения см. выше.
Возвращает:
дескриптор метода, реализующий цикл while, описанный аргументами.
Исключения:
IllegalArgumentException — если нарушены правила для аргументов.
NullPointerException — если pred или body являются null.
Начиная с версии:
9
См. также:
  • loop(MethodHandle[][])
  • whileLoop(MethodHandle, MethodHandle, MethodHandle)

countedLoop

public static MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body)
Создает цикл, выполняющий заданное число итераций. Это удобная обертка для универсального комбинатора циклов.

Число итераций определяется результатом вычисления дескриптора iterations. Счетчик цикла i — это дополнительная переменная итерации цикла типа int. Она инициализируется значением 0 и увеличивается на 1 в каждой итерации.

Если дескриптор body возвращает тип void, отличный от V, также присутствует ведущая переменная итерации цикла этого типа. Эта переменная инициализируется с помощью необязательного дескриптора init либо значением по умолчанию типа V, если этот дескриптор равен null.

В каждой итерации переменные итерации передаются при вызове дескриптора body. Возвращаемое телом цикла значение типа V, отличное от void, обновляет ведущую переменную итерации. Результатом выполнения дескриптора цикла будет итоговое значение V этой переменной (или void, если переменная V отсутствует).

Для дескрипторов-аргументов действуют следующие правила:

  • Дескриптор iterations не должен быть null и должен возвращать тип int, далее обозначаемый как I в списках типов параметров.
  • Дескриптор body не должен быть null; его тип должен иметь вид (V I A...)V, где V — тип, отличный от void, либо (I A...)void. (В случае void мы присваиваем тип void имени V и будем записывать (V I A...)V, подразумевая, что тип void V незаметно исключается из списка параметров, оставляя (I A...)V.)
  • Список параметров (V I A...) тела цикла вносит вклад в список типов, называемый внутренним списком параметров. Он будет ограничивать списки параметров остальных частей цикла.
  • В особом случае, если тело цикла вносит только типы V и I, без дополнительных типов A, внутренний список параметров расширяется типами аргументов A... дескриптора iterations.
  • Если типы переменных итерации (V I) исключить из внутреннего списка параметров, полученный более короткий список (A...) называется внешним списком параметров.
  • Тип возвращаемого телом цикла значения V, если он отличается от void, определяет тип дополнительной переменной состояния цикла. Тело цикла должно принимать параметр этого типа в начале списка и возвращать значение типа V.
  • Если init отличается от null, его тип возвращаемого значения должен быть V. Его список параметров (некоторой формы (A*)) должен быть эффективно идентичен внешнему списку параметров (A...).
  • Если init равен null, переменная цикла будет инициализирована своим значением по умолчанию.
  • Список параметров iterations (некоторой формы (A*)) должен быть эффективно идентичен внешнему списку параметров (A...).

Тип результата и сигнатура параметров полученного дескриптора цикла определяются следующим образом:

  • Тип результата дескриптора цикла — это тип результата V тела цикла.
  • Типы параметров дескриптора цикла — это типы (A...) из внешнего списка параметров.

Ниже приведен псевдокод полученного дескриптора цикла. В коде V/v обозначают тип / значение второй переменной цикла, а также тип результата цикла; A.../a... обозначают аргументы, передаваемые циклу.

int iterations(A...);
V init(A...);
V body(V, int, A...);
V countedLoop(A... a...) {
  int end = iterations(a...);
  V v = init(a...);
  for (int i = 0; i < end; ++i) {
    v = body(v, i, a...);
  }
  return v;
}
Примечание API:
Пример с полностью соответствующим требованиям методом тела цикла:
// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
// => a variation on a well known theme
static String step(String v, int counter, String init) { return "na " + v; }
// assume MH_step is a handle to the method above
MethodHandle fit13 = MethodHandles.constant(int.class, 13);
MethodHandle start = MethodHandles.identity(String.class);
MethodHandle loop = MethodHandles.countedLoop(fit13, start, MH_step);
assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
, пример с методом тела цикла простейшего возможного типа, в котором число итераций передается при вызове цикла:
// String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
// => a variation on a well known theme
static String step(String v, int counter ) { return "na " + v; }
// assume MH_step is a handle to the method above
MethodHandle count = MethodHandles.dropArguments(MethodHandles.identity(int.class), 1, String.class);
MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class);
MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step);  // (v, i) -> "na " + v
assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "Lambdaman!"));
, пример, в котором число итераций, строка для добавления и добавляемая строка рассматриваются как параметры цикла:
// String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;
// => a variation on a well known theme
static String step(String v, int counter, int iterations_, String pre, String start_) { return pre + " " + v; }
// assume MH_step is a handle to the method above
MethodHandle count = MethodHandles.identity(int.class);
MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class, String.class);
MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step);  // (v, i, _, pre, _) -> pre + " " + v
assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "na", "Lambdaman!"));
, пример, иллюстрирующий использование dropArgumentsToMatch(MethodHandle, int, List, int) для задания типа цикла:
// String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;
// => a variation on a well known theme
static String step(String v, int counter, String pre) { return pre + " " + v; }
// assume MH_step is a handle to the method above
MethodType loopType = methodType(String.class, String.class, int.class, String.class);
MethodHandle count = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(int.class),    0, loopType.parameterList(), 1);
MethodHandle start = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(String.class), 0, loopType.parameterList(), 2);
MethodHandle body  = MethodHandles.dropArgumentsToMatch(MH_step,                              2, loopType.parameterList(), 0);
MethodHandle loop = MethodHandles.countedLoop(count, start, body);  // (v, i, pre, _, _) -> pre + " " + v
assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("na", 13, "Lambdaman!"));
, реализацию этого метода можно выразить следующим образом:
MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
    return countedLoop(empty(iterations.type()), iterations, init, body);
}
Параметры:
iterations — дескриптор, отличный от null, возвращающий число итераций, которые должен выполнить этот цикл. Тип результата дескриптора должен быть int. Другие ограничения см. выше.
init — необязательный инициализатор, задающий начальное значение переменной цикла. Может быть равен null, что означает использование начального значения по умолчанию. Другие ограничения см. выше.
body — тело цикла, которое не может быть null. В стандартном случае оно определяет параметры цикла и тип результата (подробности см. выше). Оно должно принимать собственный тип возвращаемого значения (если он не void), а также параметр типа int (для счетчика) и может принимать любое число дополнительных типов. Другие ограничения см. выше.
Возвращает:
дескриптор метода, представляющий цикл.
Вызывает:
NullPointerException — если любой из дескрипторов iterations или body равен null.
IllegalArgumentException — если какой-либо аргумент нарушает сформулированные выше правила.
С версии:
9
См. также:
  • countedLoop(MethodHandle, MethodHandle, MethodHandle, MethodHandle)

countedLoop

public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body)
Создает цикл, проходящий по диапазону чисел. Это удобная обертка для универсального комбинатора циклов.

Счетчик цикла i — это переменная итерации цикла типа int. Дескрипторы start и end задают начальное (включительно) и конечное (исключительно) значения счетчика цикла. Счетчик цикла инициализируется значением int, возвращенным при вычислении дескриптора start, и увеличивается до значения, возвращенного дескриптором end (не включая его), с шагом 1.

Если дескриптор body возвращает тип void, отличный от V, также присутствует ведущая переменная итерации цикла этого типа. Эта переменная инициализируется с помощью необязательного дескриптора init либо значением по умолчанию типа V, если этот дескриптор равен null.

В каждой итерации переменные итерации передаются при вызове дескриптора body. Возвращаемое телом цикла значение типа V, отличное от void, обновляет ведущую переменную итерации. Результатом выполнения дескриптора цикла будет итоговое значение V этой переменной (или void, если переменная V отсутствует).

Для дескрипторов-аргументов действуют следующие правила:

  • Дескрипторы start и end не должны быть null и должны оба возвращать общий тип int, далее обозначаемый как I в списках типов параметров.
  • Дескриптор body не должен быть null; его тип должен иметь вид (V I A...)V, где V — тип, отличный от void, либо (I A...)void. (В случае void мы присваиваем тип void имени V и будем записывать (V I A...)V, подразумевая, что тип void V незаметно исключается из списка параметров, оставляя (I A...)V.)
  • Список параметров (V I A...) тела цикла вносит вклад в список типов, называемый внутренним списком параметров. Он будет ограничивать списки параметров остальных частей цикла.
  • В особом случае, если тело цикла вносит только типы V и I, без дополнительных типов A, внутренний список параметров расширяется типами аргументов A... дескриптора end.
  • Если типы переменных итерации (V I) исключить из внутреннего списка параметров, полученный более короткий список (A...) называется внешним списком параметров.
  • Тип возвращаемого телом цикла значения V, если он отличается от void, определяет тип дополнительной переменной состояния цикла. Тело цикла должно принимать параметр этого типа в начале списка и возвращать значение типа V.
  • Если init отличается от null, его тип возвращаемого значения должен быть V. Его список параметров (некоторой формы (A*)) должен быть эффективно идентичен внешнему списку параметров (A...).
  • Если init равен null, переменная цикла будет инициализирована своим значением по умолчанию.
  • Список параметров start (некоторой формы (A*)) должен быть эффективно идентичен внешнему списку параметров (A...).
  • Аналогично, список параметров end должен быть эффективно идентичен внешнему списку параметров.

Тип результата и сигнатура параметров полученного дескриптора цикла определяются следующим образом:

  • Тип результата дескриптора цикла — это тип результата V тела цикла.
  • Типы параметров дескриптора цикла — это типы (A...) из внешнего списка параметров.

Ниже приведен псевдокод полученного дескриптора цикла. В коде V/v обозначают тип / значение второй переменной цикла, а также тип результата цикла; A.../a... обозначают аргументы, передаваемые циклу.

int start(A...);
int end(A...);
V init(A...);
V body(V, int, A...);
V countedLoop(A... a...) {
  int e = end(a...);
  int s = start(a...);
  V v = init(a...);
  for (int i = s; i < e; ++i) {
    v = body(v, i, a...);
  }
  return v;
}
Примечание API:
Реализацию этого метода можно выразить следующим образом:
MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
    MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, int.class, int.class);
    // assume MH_increment and MH_predicate are handles to implementation-internal methods with
    // the following semantics:
    // MH_increment: (int limit, int counter) -> counter + 1
    // MH_predicate: (int limit, int counter) -> counter < limit
    Class<?> counterType = start.type().returnType();  // int
    Class<?> returnType = body.type().returnType();
    MethodHandle incr = MH_increment, pred = MH_predicate, retv = null;
    if (returnType != void.class) {  // ignore the V variable
        incr = dropArguments(incr, 1, returnType);  // (limit, v, i) => (limit, i)
        pred = dropArguments(pred, 1, returnType);  // ditto
        retv = dropArguments(identity(returnType), 0, counterType); // ignore limit
    }
    body = dropArguments(body, 0, counterType);  // ignore the limit variable
    MethodHandle[]
        loopLimit  = { end, null, pred, retv }, // limit = end(); i < limit || return v
        bodyClause = { init, body },            // v = init(); v = body(v, i)
        indexVar   = { start, incr };           // i = start(); i = i + 1
    return loop(loopLimit, bodyClause, indexVar);
}
Параметры:
start — дескриптор, отличный от null, возвращающий начальное значение счетчика цикла, которое должно быть int. Другие ограничения см. выше.
end — дескриптор, отличный от null, возвращающий конечное значение счетчика цикла (цикл будет выполняться до end-1). Тип результата должен быть int. Другие ограничения см. выше.
init — необязательный инициализатор, задающий начальное значение переменной цикла. Может быть равен null, что означает использование начального значения по умолчанию. Другие ограничения см. выше.
body — тело цикла, которое не может быть null. В стандартном случае оно определяет параметры цикла и тип результата (подробности см. выше). Оно должно принимать собственный тип возвращаемого значения (если он не void), а также параметр типа int (для счетчика) и может принимать любое число дополнительных типов. Другие ограничения см. выше.
Возвращает:
дескриптор метода, представляющий цикл.
Вызывает:
NullPointerException — если любой из дескрипторов start, end или body равен null.
IllegalArgumentException — если какой-либо аргумент нарушает сформулированные выше правила.
С версии:
9
См. также:
  • countedLoop(MethodHandle, MethodHandle, MethodHandle)

iteratedLoop

public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body)
Создает цикл, проходящий по значениям, полученным из Iterator<T>. Это удобная обертка для универсального комбинатора циклов.

Сам итератор определяется при вычислении дескриптора iterator. Каждое полученное им значение сохраняется в переменной итерации цикла типа T.

Если дескриптор body возвращает тип void, отличный от V, также присутствует ведущая переменная итерации цикла этого типа. Эта переменная инициализируется с помощью необязательного дескриптора init либо значением по умолчанию типа V, если этот дескриптор равен null.

В каждой итерации переменные итерации передаются при вызове дескриптора body. Возвращаемое телом цикла значение типа V, отличное от void, обновляет ведущую переменную итерации. Результатом выполнения дескриптора цикла будет итоговое значение V этой переменной (или void, если переменная V отсутствует).

Для дескрипторов-аргументов действуют следующие правила:

  • Дескриптор body не должен быть null; его тип должен иметь вид (V T A...)V, где V — тип, отличный от void, либо (T A...)void. (В случае void мы присваиваем тип void имени V и будем записывать (V T A...)V, подразумевая, что тип void V незаметно исключается из списка параметров, оставляя (T A...)V.)
  • Список параметров (V T A...) тела цикла вносит вклад в список типов, называемый внутренним списком параметров. Он будет ограничивать списки параметров остальных частей цикла.
  • В особом случае, если тело цикла вносит только типы V и T, без дополнительных типов A, внутренний список параметров расширяется типами аргументов A... дескриптора iterator; если он равен null, добавляется единственный тип Iterable, который образует список A....
  • Если типы переменных итерации (V T) исключить из внутреннего списка параметров, полученный более короткий список (A...) называется внешним списком параметров.
  • Тип возвращаемого телом цикла значения V, если он отличается от void, определяет тип дополнительной переменной состояния цикла. Тело цикла должно принимать параметр этого типа в начале списка и возвращать значение типа V.
  • Если init отличается от null, его тип возвращаемого значения должен быть V. Его список параметров (некоторой формы (A*)) должен быть эффективно идентичен внешнему списку параметров (A...).
  • Если init равен null, переменная цикла будет инициализирована своим значением по умолчанию.
  • Если дескриптор iterator отличен от null, он должен иметь тип возвращаемого значения java.util.Iterator или его подтип. Будет считаться, что итератор, созданный им при выполнении цикла, выдает значения, которые можно преобразовать к типу T.
  • Список параметров iterator, отличного от null (некоторой формы (A*)), должен быть эффективно идентичен внешнему списку параметров (A...).
  • Если iterator равен null, по умолчанию используется дескриптор метода, поведение которого соответствует Iterable.iterator(). В этом случае внутренний список параметров (V T A...) должен содержать как минимум один тип A, а параметр дескриптора итератора, используемого по умолчанию, настраивается для приема ведущего типа A, как если бы выполнялось преобразование методом asType. Ведущий тип A должен быть Iterable или его подтипом. Этот шаг преобразования, выполняемый при создании цикла, не должен вызывать WrongMethodTypeException.

Тип T может быть как примитивным, так и ссылочным. Поскольку тип Iterator<T> в представлении дескриптора метода стирается до исходного типа Iterator, комбинатор iteratedLoop настраивает ведущий тип аргумента для body на Object, как если бы выполнялось преобразование методом asType. Поэтому, если во время выполнения цикла встретится итератор неправильного типа, могут возникнуть исключения времени выполнения в результате динамических преобразований, выполняемых методом MethodHandle.asType(MethodType).

Тип результата и сигнатура параметров полученного дескриптора цикла определяются следующим образом:

  • Тип результата дескриптора цикла — это тип результата V тела цикла.
  • Типы параметров дескриптора цикла — это типы (A...) из внешнего списка параметров.

Ниже приведен псевдокод полученного дескриптора цикла. В коде V/v обозначают тип / значение переменной цикла, а также тип результата цикла; T/t — тип / значение элементов структуры, по которой проходит цикл; A.../a... обозначают аргументы, передаваемые циклу.

Iterator<T> iterator(A...);  // defaults to Iterable::iterator
V init(A...);
V body(V,T,A...);
V iteratedLoop(A... a...) {
  Iterator<T> it = iterator(a...);
  V v = init(a...);
  while (it.hasNext()) {
    T t = it.next();
    v = body(v, t, a...);
  }
  return v;
}
Примечание API:
Пример:
// get an iterator from a list
static List<String> reverseStep(List<String> r, String e) {
  r.add(0, e);
  return r;
}
static List<String> newArrayList() { return new ArrayList<>(); }
// assume MH_reverseStep and MH_newArrayList are handles to the above methods
MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");
assertEquals(reversedList, (List<String>) loop.invoke(list));
, реализацию этого метода можно приблизительно выразить следующим образом:
MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
    // assume MH_next, MH_hasNext, MH_startIter are handles to methods of Iterator/Iterable
    Class<?> returnType = body.type().returnType();
    Class<?> ttype = body.type().parameterType(returnType == void.class ? 0 : 1);
    MethodHandle nextVal = MH_next.asType(MH_next.type().changeReturnType(ttype));
    MethodHandle retv = null, step = body, startIter = iterator;
    if (returnType != void.class) {
        // the simple thing first:  in (I V A...), drop the I to get V
        retv = dropArguments(identity(returnType), 0, Iterator.class);
        // body type signature (V T A...), internal loop types (I V A...)
        step = swapArguments(body, 0, 1);  // swap V <-> T
    }
    if (startIter == null)  startIter = MH_getIter;
    MethodHandle[]
        iterVar    = { startIter, null, MH_hasNext, retv }, // it = iterator; while (it.hasNext())
        bodyClause = { init, filterArguments(step, 0, nextVal) };  // v = body(v, t, a)
    return loop(iterVar, bodyClause);
}
Параметры:
iterator — необязательный дескриптор, возвращающий итератор, с которого начинается цикл. Если он отличен от null, дескриптор должен возвращать Iterator или его подтип. Другие ограничения см. выше.
init — необязательный инициализатор, задающий начальное значение переменной цикла. Может быть равен null, что означает использование начального значения по умолчанию. Другие ограничения см. выше.
body — тело цикла, которое не может быть null. В стандартном случае оно определяет параметры цикла и тип результата (подробности см. выше). Оно должно принимать собственный тип возвращаемого значения (если он не void), а также параметр типа T (для перебираемых значений) и может принимать любое число дополнительных типов. Другие ограничения см. выше.
Возвращает:
дескриптор метода, реализующий функциональность цикла итерации.
Вызывает:
NullPointerException — если дескриптор body равен null.
IllegalArgumentException — если какой-либо аргумент нарушает перечисленные выше требования.
С версии:
9

tryFinally

public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup)
Создает дескриптор метода, адаптирующий дескриптор метода target путем его оборачивания в блок try-finally. Другой дескриптор метода, cleanup, представляет функциональность блока finally. Любое исключение, возникшее во время выполнения дескриптора target, передается дескриптору cleanup. Исключение повторно выбрасывается, если только дескриптор cleanup не выбросит исключение раньше. Значение, возвращенное при выполнении дескриптора cleanup, будет результатом выполнения дескриптора try-finally.

Дескриптору cleanup передаются один или два дополнительных ведущих аргумента. Первый — исключение, возникшее во время выполнения дескриптора target, либо null, если исключение не возникло. Второй — результат выполнения дескриптора target либо, если он выбрасывает исключение, значение null, ноль или false требуемого типа, передаваемое в качестве заполнителя. Второй аргумент отсутствует, если дескриптор target имеет тип возвращаемого значения void. (Обратите внимание: за исключением преобразований типов аргументов, комбинаторы представляют значения void в списках параметров, опуская соответствующие парадоксальные аргументы, а не вставляя значения null или нулевые значения.)

Дескрипторы target и cleanup должны иметь одинаковые соответствующие типы аргументов и возвращаемые типы, за исключением того, что дескриптор cleanup может не содержать завершающие аргументы. Кроме того, дескриптор cleanup должен иметь один или два дополнительных ведущих параметра:

  • Throwable, который будет содержать исключение, возникшее в дескрипторе target (если таковое возникло); и
  • параметр того же типа, что и тип возвращаемого значения дескрипторов target и cleanup, который будет содержать результат выполнения дескриптора target. Этот параметр отсутствует, если дескриптор target возвращает void.

Псевдокод полученного адаптера выглядит следующим образом. В коде V обозначает тип результата конструкции try/finally; A/a — типы и значения аргументов полученного дескриптора, используемых блоком очистки; B/b — типы и значения аргументов полученного дескриптора, отбрасываемых блоком очистки.

V target(A..., B...);
V cleanup(Throwable, V, A...);
V adapter(A... a, B... b) {
  V result = (zero value for V);
  Throwable throwable = null;
  try {
    result = target(a..., b...);
  } catch (Throwable t) {
    throwable = t;
    throw t;
  } finally {
    result = cleanup(throwable, result, a...);
  }
  return result;
}

Обратите внимание, что сохраненные аргументы (a... в псевдокоде) не могут быть изменены при выполнении целевого дескриптора и поэтому, если блок очистки вызывается, передаются ему без изменений от вызывающего кода.

Целевой дескриптор и блок очистки должны возвращать один и тот же тип, даже если блок очистки всегда выбрасывает исключение. Чтобы создать такой блок очистки, выбрасывающий исключение, объедините логику очистки с throwException, чтобы получить дескриптор метода с правильным типом возвращаемого значения.

Обратите внимание, что tryFinally никогда не преобразует исключения в обычные возвращаемые значения. В редких случаях, когда исключения требуется преобразовывать таким образом, сначала оберните целевой дескриптор с помощью catchException(MethodHandle, Class, MethodHandle), чтобы перехватить исходящее исключение, а затем оберните его с помощью tryFinally.

Рекомендуется объявлять первый тип параметра cleanup как Throwable, а не как более узкий подтип. Это гарантирует, что cleanup всегда будет вызван с любым исключением, выброшенным target. Объявление более узкого типа может привести к тому, что дескриптор try-finally выбросит ClassCastException, если тип исключения, выброшенного target, нельзя присвоить первому типу параметра cleanup. Обратите внимание, что исключения различных типов — VirtualMachineError, LinkageError и RuntimeException — теоретически могут быть выброшены практически любым кодом Java, и блок finally, перехватывающий, например, только IOException, замаскирует остальные исключения за ClassCastException.

Параметры:
target — дескриптор, выполнение которого следует обернуть в блок try.
cleanup — дескриптор, вызываемый в блоке finally.
Возвращает:
дескриптор метода, реализующий блок try-finally, составленный из двух аргументов.
Вызывает:
NullPointerException — если какой-либо аргумент равен null
IllegalArgumentException — если cleanup не принимает необходимые ведущие аргументы либо если типы дескрипторов метода не совпадают по типам возвращаемых значений и соответствующим завершающим параметрам
С версии:
9
См. также:
  • catchException(MethodHandle, Class, MethodHandle)

tableSwitch

public static MethodHandle tableSwitch(MethodHandle fallback, MethodHandle... targets)
Создает дескриптор метода табличного переключения, который можно использовать для выбора одного из целевых дескрипторов метода на основе заданного индекса цели, называемого селектором.

Если значение селектора равно n, где n находится в диапазоне [0, N), а N — это число целевых дескрипторов метода, дескриптор метода табличного переключения вызовет n-й целевой дескриптор метода из списка целевых дескрипторов.

Если значение селектора не входит в диапазон [0, N), дескриптор метода табличного переключения вызовет заданный резервный дескриптор метода.

Все передаваемые этому методу дескрипторы метода должны иметь одинаковый тип; кроме того, их ведущий параметр должен иметь тип int. Ведущий параметр представляет селектор.

Все завершающие параметры, присутствующие в типе, также будут присутствовать в возвращаемом дескрипторе метода табличного переключения. Значения, переданные этим параметрам, будут пересылаться вместе со значением селектора выбранному дескриптору метода при его вызове.

Примечание API:
Пример: в каждом случае отбрасывается полученное значение selector и принимается дополнительный аргумент String, который объединяется (с помощью String.concat(String)) с постоянной строкой-меткой, заданной для этого случая:
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle caseMh = lookup.findVirtual(String.class, "concat",
        MethodType.methodType(String.class, String.class));
caseMh = MethodHandles.dropArguments(caseMh, 0, int.class);

MethodHandle caseDefault = MethodHandles.insertArguments(caseMh, 1, "default: ");
MethodHandle case0 = MethodHandles.insertArguments(caseMh, 1, "case 0: ");
MethodHandle case1 = MethodHandles.insertArguments(caseMh, 1, "case 1: ");

MethodHandle mhSwitch = MethodHandles.tableSwitch(
    caseDefault,
    case0,
    case1
);

assertEquals("default: data", (String) mhSwitch.invokeExact(-1, "data"));
assertEquals("case 0: data", (String) mhSwitch.invokeExact(0, "data"));
assertEquals("case 1: data", (String) mhSwitch.invokeExact(1, "data"));
assertEquals("default: data", (String) mhSwitch.invokeExact(2, "data"));
Параметры:
fallback — резервный дескриптор метода, вызываемый, если селектор не входит в диапазон [0, N).
targets — массив целевых дескрипторов метода.
Возвращает:
дескриптор метода табличного переключения.
Вызывает:
NullPointerException — если fallback, массив targets или какой-либо элемент массива targets равен null.
IllegalArgumentException — если массив targets пуст, если ведущий параметр резервного дескриптора или любого целевого дескриптора не имеет тип int либо если типы резервного дескриптора и всех целевых дескрипторов различаются.
С версии:
17

filterValue

public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
Адаптирует целевой var handle, предварительно обрабатывая входящие и исходящие значения с помощью пары функций-фильтров.

При вызове, например, VarHandle.set(Object...) для полученного var handle входящее значение (типа T, где T — последний тип параметра первой функции-фильтра) обрабатывается первым фильтром, а затем передаётся целевому var handle. И наоборот, при вызове, например, VarHandle.get(Object...) для полученного var handle возвращаемое значение, полученное от целевого var handle (типа T, где T — последний тип параметра второй функции-фильтра), обрабатывается вторым фильтром и возвращается вызывающему коду. Более сложные типы режимов доступа, такие как VarHandle.AccessMode.COMPARE_AND_EXCHANGE, могут применять оба фильтра одновременно.

Чтобы фильтры упаковки и распаковки были корректно сформированы, их типы должны иметь вид (A... , S) -> T и (A... , T) -> S соответственно, где T — тип целевого var handle. В этом случае полученный var handle будет иметь тип S и дополнительные координаты A... (которые будут добавлены к координатам целевого var handle).

Если при вызове фильтры упаковки и распаковки выбросят проверяемые исключения, полученный var handle выбросит IllegalStateException.

Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.

Параметры:
target — целевой var handle
filterToTarget — фильтр для преобразования типа S в тип target
filterFromTarget — фильтр для преобразования типа target в тип S
Возвращает:
адаптер var handle, принимающий новый тип и выполняющий указанные преобразования упаковки/распаковки.
Выбрасывает:
IllegalArgumentException — если filterFromTarget и filterToTarget сформированы некорректно, то есть имеют типы, отличные от (A... , S) -> T и (A... , T) -> S соответственно, где T — тип целевого var handle, либо если установлено, что filterFromTarget или filterToTarget выбрасывает проверяемые исключения.
NullPointerException — если любой из аргументов равен null.
Начиная с версии:
22

filterCoordinates

public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters)
Адаптирует целевой var handle, предварительно обрабатывая входящие значения координат с помощью унарных функций-фильтров.

При вызове, например, VarHandle.get(Object...) для полученного var handle входящие значения координат, начиная с позиции pos (типа C1, C2 ... Cn, где C1, C2 ... Cn — типы возвращаемых значений унарных функций-фильтров), преобразуются в новые значения (типа S1, S2 ... Sn, где S1, S2 ... Sn — типы параметров унарных функций-фильтров), а затем передаются целевому var handle вместе с координатами, не изменёнными при адаптации.

Чтобы фильтры координат были корректно сформированы, их типы должны иметь вид S1 -> T1, S2 -> T1 ... Sn -> Tn, где T1, T2 ... Tn — типы координат целевого var handle, начиная с позиции pos.

Если при вызове какой-либо фильтр выбросит проверяемое исключение, полученный var handle выбросит IllegalStateException.

Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.

Параметры:
target — целевой var handle
pos — позиция первой преобразуемой координаты
filters — унарные функции для преобразования координат, начиная с позиции pos
Возвращает:
адаптер var handle, принимающий новые типы координат и применяющий указанное преобразование к новым значениям координат.
Выбрасывает:
IllegalArgumentException — если дескрипторы в filters сформированы некорректно, то есть имеют типы, отличные от S1 -> T1, S2 -> T2, ... Sn -> Tn, где T1, T2 ... Tn — типы координат целевого var handle, начиная с позиции pos, если pos не находится в диапазоне от 0 до арности координат целевого var handle включительно, если фильтров больше, чем доступных типов координат, начиная с pos, либо если установлено, что какой-либо из фильтров выбрасывает проверяемые исключения.
NullPointerException — если любой из аргументов равен null или filters содержит null.
Начиная с версии:
22

insertCoordinates

public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values)
Предоставляет целевому var handle одну или несколько связанных координат до вызова var handle. В результате полученный var handle будет иметь меньше типов координат, чем целевой var handle.

При вызове, например, VarHandle.get(Object...) для полученного var handle входящие значения координат объединяются со связанными значениями координат, а затем передаются целевому var handle.

Чтобы связанные координаты были корректно сформированы, их типы должны быть T1, T2 ... Tn , где T1, T2 ... Tn — типы координат целевого var handle, начиная с позиции pos.

Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.

Параметры:
target — var handle, вызываемый после вставки связанных координат
pos — позиция первой вставляемой координаты
values — последовательность вставляемых связанных координат
Возвращает:
адаптер var handle, вставляющий дополнительные координаты перед вызовом целевого var handle
Выбрасывает:
IllegalArgumentException — если pos не находится в диапазоне от 0 до арности координат целевого var handle включительно либо если предоставлено больше значений, чем доступных типов координат, начиная с pos.
ClassCastException — если связанные координаты в values сформированы некорректно, то есть имеют типы, отличные от T1, T2 ... Tn , где T1, T2 ... Tn — типы координат целевого var handle, начиная с позиции pos.
NullPointerException — если любой из аргументов равен null или values содержит null.
Начиная с версии:
22

permuteCoordinates

public static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder)
Предоставляет var handle, адаптирующий значения координат целевого var handle путём их перестановки так, чтобы новые координаты соответствовали указанным.

Порядок перестановки задаётся переданным массивом. Обозначим #I количество входящих координат (значение newCoordinates.size()), а #O — количество исходящих координат (количество координат целевого var handle). Тогда длина массива перестановки должна быть равна #O, а каждый его элемент должен быть неотрицательным числом, меньшим #I. Для каждого N, меньшего #O, N-я исходящая координата будет взята из I-й входящей координаты, где I равно reorder[N].

Преобразования типов координат не выполняются. Тип каждой входящей координаты, определяемый с помощью newCoordinates, должен совпадать с типом соответствующей исходящей координаты целевого var handle.

Массив перестановки не обязательно должен задавать настоящую перестановку. Входящая координата будет продублирована, если её индекс встречается в массиве более одного раза, и отброшена, если её индекс в массиве отсутствует.

Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.

Параметры:
target — var handle, вызываемый после перестановки координат
newCoordinates — новые типы координат
reorder — массив индексов, задающий порядок перестановки
Возвращает:
адаптер var handle, переставляющий входящие значения координат перед вызовом целевого var handle
Выбрасывает:
IllegalArgumentException — если длина массива индексов не равна количеству координат целевого var handle, если какой-либо элемент массива индексов не является допустимым индексом координаты для newCoordinates либо если типы соответствующих координат в целевом var handle и в newCoordinates не совпадают.
NullPointerException — если любой из аргументов равен null или newCoordinates содержит null.
Начиная с версии:
22

collectCoordinates

public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter)
Адаптирует целевой var handle, предварительно обрабатывая подпоследовательность его значений координат с помощью фильтра (дескриптора метода). Предварительно обработанные координаты заменяются результатом функции-фильтра (если он есть), после чего целевой var handle вызывается с изменённым (обычно сокращённым) списком координат.

Если R — тип возвращаемого значения фильтра, то:

  • если R не является void, целевой var handle должен иметь координату типа R в позиции pos. Типы параметров фильтра заменят тип координаты в позиции pos целевого var handle. При вызове возвращённого var handle фильтр сначала вызывается, а его результат передаётся вместо координаты в позиции pos при последующем вызове целевого var handle.
  • если R является void, типы параметров фильтра (если они есть) будут вставлены в список типов координат целевого var handle в позиции pos. В этом случае при вызове возвращённого var handle фильтр фактически выполняет побочное действие: принимает некоторые значения координат, после чего происходит последующий вызов целевого var handle.

Если при вызове какой-либо фильтр выбросит проверяемое исключение, полученный var handle выбросит IllegalStateException.

Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.

Параметры:
target — var handle, вызываемый после фильтрации координат
pos — позиция в списке координат целевого var handle, в которую вставляется фильтр
filter — дескриптор метода-фильтра
Возвращает:
адаптер var handle, фильтрующий входящие значения координат перед вызовом целевого var handle
Выбрасывает:
IllegalArgumentException — если возвращаемый тип filter не равен void и не совпадает с типом pos-й координаты целевого var handle, если pos не находится в диапазоне от 0 до арности координат целевого var handle включительно, если тип полученного var handle содержит слишком много координат либо если установлено, что filter выбрасывает проверяемые исключения.
NullPointerException — если любой из аргументов равен null.
Начиная с версии:
22

dropCoordinates

public static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes)
Возвращает var handle, который отбрасывает некоторые фиктивные координаты перед передачей вызова целевому var handle. В результате полученный var handle будет иметь больше типов координат, чем целевой var handle.

Значение аргумента pos может находиться в диапазоне от нуля до N, где N — арность типов координат целевого var handle. Если pos равно нулю, фиктивные координаты будут предшествовать реальным аргументам целевого var handle; если pos равно N, они будут следовать за ними.

Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.

Параметры:
target — var handle, вызываемый после отбрасывания фиктивных координат
pos — позиция первой отбрасываемой координаты (ноль для самой левой)
valueTypes — тип или типы отбрасываемых координат
Возвращает:
адаптер var handle, отбрасывающий некоторые фиктивные координаты перед вызовом целевого var handle
Выбрасывает:
IllegalArgumentException — если pos не находится в диапазоне от 0 до арности координат целевого var handle включительно.
NullPointerException — если любой из аргументов равен null или valueTypes содержит null.
Начиная с версии:
22

Сообщить об ошибке или предложить улучшение
Дополнительные справочные материалы по API и документацию для разработчиков см. в разделе Документация Java SE, содержащем более подробные описания для разработчиков, концептуальные обзоры, определения терминов, способы обхода проблем и работающие примеры кода. Другие версии.
Java является товарным знаком или зарегистрированным товарным знаком Oracle и/или её дочерних компаний в США и других странах.
Авторские права © 1993, 2025, Oracle и/или её дочерние компании, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.
Все права защищены. Использование регулируется условиями лицензии и политикой распространения документации.

© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/invoke/MethodHandles.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API