Spec-Zone.ru › OpenJDK 21

Класс MethodHandles

java.lang.Object
java.lang.invoke.MethodHandles
public 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)
Предварительный просмотр.
Адаптирует целевой обработчик переменных, предварительно обрабатывая подпоследовательность значений его координат с помощью фильтра (обработчика метода).
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)
Предварительный просмотр.
Возвращает обработчик переменных, который отбросит некоторые фиктивные координаты перед делегированием целевому обработчику переменных.
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)
Предварительный просмотр.
Адаптирует целевой обработчик переменных путём предварительной обработки входящих значений координат с использованием функций фильтрации.
static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter)
Адаптирует целевой обработчик метода, пост-обрабатывая его возвращаемое значение (если таковое имеется) с помощью фильтра (другой обработчик метода).
static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
Предварительный просмотр.
Адаптирует целевой обработчик переменных, предварительно обрабатывая входящие и исходящие значения с помощью пары функций фильтрации.
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)
Предварительный просмотр.
Предоставляет целевому обработчику переменных один или несколько связанных координат заранее перед вызовом обработчика переменных.
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 VarHandle memorySegmentViewVarHandle(ValueLayoutPREVIEW layout)
Предварительный просмотр.
Создаёт объект обработчика переменных, который может использоваться для декодирования сегмента памятиПРЕДПРОСМОТР по заданному байтовому смещению, используя предоставленное расположение значения.
static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder)
Создаёт обработчик метода, адаптирующий последовательность вызовов данного обработчика метода к новому типу путём переупорядочения аргументов.
static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder)
Предварительный просмотр.
Предоставляет обработчик переменных, который адаптирует значения координат целевого обработчика переменных, переупорядочивая их таким образом, чтобы новые координаты соответствовали предоставленным.
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)
Создаёт постоянный обработчик метода запрошенного типа возврата, который возвращает значение по умолчанию для этого типа каждый раз при вызове.

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

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

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

lookup

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

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

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

publicLookup

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

В соответствии с соглашениями, классом lookup данного объекта lookup будет Object.

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

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

Возвращает:
объект lookup, которому доверяют минимально

privateLookupIn

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

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

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

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

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

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

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

Примечание API:
Объект Lookup, возвращаемый данным методом, может определять классы в пакете runtime targetClass. Следует проявлять особую осторожность при открытии пакета для другого модуля, так как определённые таким образом классы имеют такой же полный доступ с привилегиями, как и другие члены модуля targetClass.
Параметры:
targetClass - целевой класс
caller - объект lookup вызывающего объекта
Возвращает:
объект lookup для целевого класса с приватным доступом
Выбрасывает:
IllegalArgumentException - если targetClass является примитивным типом, void или классом массива
NullPointerException - если targetClass или caller являются null
SecurityException - если запрещено системным менеджером безопасности
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 возвращается, если этот метод вызывается для объекта поиска для этих классов.

Режимы поиска (lookup modes) для этого поиска должны иметь оригинальный доступ для получения данных класса.

API Note:
Этот метод может быть вызван как метод загрузки для динамически вычисляемой константы. Фреймворк может создать скрытый класс с данными класса, например, который может быть Class или MethodHandle объектом. Данные класса доступны только для объекта поиска, созданного исходным вызывающим объектом, но недоступны для других членов в том же вложенном блоке. Если фреймворк передает чувствительные к безопасности объекты скрытому классу через данные класса, рекомендуется загрузить значение данных класса как динамически вычисляемую константу вместо хранения данных класса в частном(ых) статическом(их) поле(ях), которые доступны другим членам в том же вложенном блоке.
Type Parameters:
T - тип для приведения объекта данных класса
Parameters:
caller - контекст поиска, описывающий класс, выполняющий операцию (обычно стекируется JVM)
name - должен быть ConstantDescs.DEFAULT_NAME ("_")
type - тип данных класса
Returns:
значение данных класса, если оно присутствует в классе поиска; в противном случае null
Throws:
IllegalArgumentException - если имя не "_"
IllegalAccessException - если контекст поиска не имеет оригинального доступа
ClassCastException - если данные класса не могут быть приведены к заданному типу type
NullPointerException - если caller или type аргумент null
See Java Virtual Machine Specification:
5.5 Инициализация
Since:
16
See Also:
  • 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 возвращается, если этот метод вызывается для объекта поиска для этих классов.

Режимы поиска (lookup modes) для этого поиска должны иметь оригинальный доступ для получения данных класса.

API Note:
Этот метод может быть вызван как метод загрузки для динамически вычисляемой константы. Фреймворк может создать скрытый класс с данными класса, например, который может быть List.of(o1, o2, o3....), содержащий более одного объекта, и использовать этот метод для загрузки одного элемента по определенному индексу. Данные класса доступны только для объекта поиска, созданного исходным вызывающим объектом, но недоступны для других членов в том же вложенном блоке. Если фреймворк передает чувствительные к безопасности объекты скрытому классу через данные класса, рекомендуется загрузить значение данных класса как динамически вычисляемую константу вместо хранения данных класса в частном(ых) статическом(их) поле(ях), которые доступны другим членам в том же вложенном блоке.
Type Parameters:
T - тип для приведения результата
Parameters:
caller - контекст поиска, описывающий класс, выполняющий операцию (обычно стекируется JVM)
name - должен быть ConstantDescs.DEFAULT_NAME ("_")
type - тип элемента по указанному индексу в данных класса
index - индекс элемента в данных класса
Returns:
элемент по указанному индексу в данных класса, если данные класса присутствуют; в противном случае null
Throws:
IllegalArgumentException - если имя не "_"
IllegalAccessException - если контекст поиска не имеет оригинального доступа
ClassCastException - если данные класса не могут быть приведены к типу List или элемент по указанному индексу не может быть приведен к заданному типу
IndexOutOfBoundsException - если индекс находится вне диапазона
NullPointerException - если caller или type аргумент null; или если операция unboxing завершается неудачей, потому что элемент по указанному индексу null
Since:
16
See Also:
  • 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 для разрешения символической ссылки на член.

Если существует менеджер безопасности, его метод checkPermission вызывается с разрешением ReflectPermission("suppressAccessChecks").

Type Parameters:
T - желаемый тип результата, либо Member, или подтип
Parameters:
expected - объект класса, представляющий желаемый тип результата T
target - прямой обработчик метода для раскрытия компонентов символической ссылки
Returns:
ссылка на метод, конструктор или поле
Throws:
SecurityException - если вызывающий не имеет привилегий для вызова setAccessible
NullPointerException - если любой из аргументов null
IllegalArgumentException - если целевой объект не является прямым обработчиком метода
ClassCastException - если член не имеет ожидаемого типа
Since:
1.8

arrayConstructor

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

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

Parameters:
arrayClass - тип массива
Returns:
обработчик метода, который может создавать массивы заданного типа
Throws:
NullPointerException - если аргумент null
IllegalArgumentException - если arrayClass не является типом массива
See Java Virtual Machine Specification:
6.5 Инструкция anewarray
Since:
9
See Also:
  • Array.newInstance(Class, int)

arrayLength

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

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

Parameters:
arrayClass - тип массива
Returns:
обработчик метода, который может извлечь длину массива заданного типа массива
Throws:
NullPointerException - если аргумент является null
IllegalArgumentException - если arrayClass не является типом массива
См. Спецификацию виртуальной машины Java:
6.5 arraylength Инструкция
Since:
9

arrayElementGetter

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

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

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

arrayElementSetter

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

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

Parameters:
arrayClass - класс массива
Returns:
обработчик метода, который может сохранять значения в массив заданного типа
Throws:
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, ссылка на массив и индекс массива проверяются. Будет брошено исключение NullPointerException, если ссылка на массив равна null, и будет брошено исключение ArrayIndexOutOfBoundsException, если индекс отрицательный или если он больше или равен длине массива.

API Note:
Битовое сравнение значений float или значений double, выполняемое режимами числового и атомарного обновления, отличается от оператора == и методов Float.equals(java.lang.Object) и Double.equals(java.lang.Object), в частности, в отношении сравнения значений NaN или сравнения -0.0 с +0.0. Следует соблюдать осторожность при выполнении операции сравнения и установки или сравнения и обмена с такими значениями, так как операция может неожиданно завершиться неудачей. Существует множество возможных значений NaN, которые считаются NaN в Java, хотя ни одна операция с плавающей точкой IEEE 754, предоставляемая Java, не может различать их. Отказ от выполнения операции может произойти, если ожидаемое или наблюдаемое значение является значением NaN и оно преобразуется (возможно, специфичным для платформы способом) в другое значение NaN и, следовательно, имеет другое битовое представление (см. Float.intBitsToFloat(int) или Double.longBitsToDouble(long) для получения дополнительной информации). Значения -0.0 и +0.0 имеют разные битовые представления, но считаются равными при использовании оператора ==. Отказ от выполнения операции может произойти, например, если числовой алгоритм вычисляет ожидаемое значение, скажем, -0.0, и ранее вычислил свидетельское значение, скажем, +0.0.
Parameters:
arrayClass - класс массива, типа T[]
Returns:
VarHandle, предоставляющий доступ к элементам массива
Throws:
NullPointerException - если arrayClass равен null
IllegalArgumentException - если arrayClass не является типом массива
Since:
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.

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

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

Невыровненный доступ, а следовательно, и гарантии атомности, могут быть определены для массивов byte[] без работы с конкретным массивом. Учитывая index, T и его соответствующий упакованный тип, T_BOX, невыравнивание может быть определено следующим образом:


 int sizeOfT = T_BOX.BYTES;  // size in bytes of T
 int misalignedAtZeroIndex = ByteBuffer.wrap(new byte[0]).
     alignmentOffset(0, sizeOfT);
 int misalignedAtIndex = (misalignedAtZeroIndex + index) % sizeOfT;
 boolean isMisaligned = misalignedAtIndex != 0;
 

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

Параметры:
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.

Обращение к любому режиму доступа, кроме чтения, вызовет исключение ReadOnlyBufferException, если ByteBuffer доступно только для чтения.

Обращение к байтам по заданному индексу приведет к исключению IndexOutOfBoundsException, если индекс меньше 0 или больше предела ByteBuffer минус размер (в байтах) T.

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

  • Режимы чтения-записи для всех T, за исключением режимов доступа get и set для long и double на 32-битных платформах.
  • Режимы атомарного обновления для 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; в противном случае, он будет вести себя так, как будто используется asType для преобразования целевого обработчика к требуемому type.

Тип возвращаемого обработчика не будет заданным 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, тип режима доступа которого соответствует заданному типу.
Since:
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, тип режима доступа которого преобразуем к заданному типу.
Since:
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 во время выполнения, вводится значение нуля.
Parameters:
target - обработчик метода, который вызывается после повторной типизации аргументов
newType - ожидаемый тип нового обработчика метода
Returns:
обработчик метода, который делегирует целевому обработчику после выполнения необходимых преобразований аргументов и организует необходимые преобразования возвращаемого значения
Throws:
NullPointerException - если любой из аргументов равен null
WrongMethodTypeException - если преобразование невозможно
See Also:
  • MethodHandle.asType(java.lang.invoke.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);

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

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

constant

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

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

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

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

identity

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

zero

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

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

Parameters:
type - ожидаемый тип возвращаемого значения желаемого обработчика метода
Returns:
обработчик константного метода, не принимающий аргументов и возвращающий значение по умолчанию заданного типа (или void, если тип void)
Throws:
NullPointerException - если аргумент равен null
Since:
9
See Also:
  • constant(java.lang.Class<?>, java.lang.Object)
  • empty(java.lang.invoke.MethodType)
  • explicitCastArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)

empty

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

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

API Note:
При заданном предикате и целевом объекте можно создать полезную конструкцию «если-то» как guardWithTest(pred, target, empty(target.type()).
Parameters:
type - тип желаемого обработчика метода
Returns:
обработчик константного метода заданного типа, который возвращает значение по умолчанию для заданного типа возвращаемого значения
Throws:
NullPointerException - если аргумент равен null
Since:
9
See Also:
  • zero(java.lang.Class<?>)
  • constant(java.lang.Class<?>, java.lang.Object)

insertArguments

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

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

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

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

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

Parameters:
target - обработчик метода, который нужно вызвать после вставки аргумента
pos - место вставки аргумента (ноль для первого)
values - серия аргументов для вставки
Returns:
обработчик метода, который вставляет дополнительный аргумент перед вызовом исходного обработчика метода
Throws:
NullPointerException - если целевой объект или массив values равен null
IllegalArgumentException - если pos меньше 0 или больше N - L, где N — арность целевого обработчика метода, а L — длина массива значений.
ClassCastException - если аргумент не соответствует соответствующему типу связанного параметра.
See Also:
  • MethodHandle.bindTo(java.lang.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]))
 
Parameters:
target - обработчик метода, который нужно вызвать после отбрасывания аргументов
pos - позиция первого аргумента для отбрасывания (ноль для левого)
valueTypes - тип(ы) аргумента(ов) для отбрасывания
Returns:
обработчик метода, который отбрасывает аргументы указанных типов перед вызовом исходного обработчика метода
Throws:
NullPointerException - если целевой объект равен null, или если список valueTypes или любой его элемент равен null
IllegalArgumentException - если любой элемент из valueTypes равен void.class, или если pos отрицательный или больше арности целевого объекта, или если у нового обработчика метода будет слишком много параметров

dropArguments

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

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

API Note:
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))
 
Parameters:
target - обработчик метода, который нужно вызвать после отбрасывания аргументов
pos - позиция первого аргумента для отбрасывания (ноль для левого)
valueTypes - тип(ы) аргумента(ов) для отбрасывания
Returns:
обработчик метода, который отбрасывает аргументы указанных типов перед вызовом исходного обработчика метода
Throws:
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 Note:
Два обработчика методов, списки аргументов которых "эффективно идентичны" (т.е. идентичны в общем префиксе), могут быть взаимно преобразованы в общий тип с помощью двух вызовов 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"));
Parameters:
target - обработчик метода для адаптации
skip - количество параметров целевого объекта, которые нужно проигнорировать (они останутся неизменными)
newTypes - список типов, с которыми необходимо сопоставить список типов параметров target
pos - место в списке newTypes, где должны находиться параметры целевого объекта, которые не были пропущены
Returns:
возможно адаптированный обработчик метода
Throws:
NullPointerException - если любой из аргументов равен null
IllegalArgumentException - если любой элемент из newTypes равен void.class, или если skip отрицательный или больше арности целевого объекта, или если pos отрицательный или больше размера списка newTypes, или если newTypes не содержит типы параметров целевого объекта, которые не были пропущены, в позиции pos.
Since:
9

dropReturn

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

filterArguments

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

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

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

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

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

Пример:

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, предшествующие и/или последующие аргументы, не переданные фильтру. Если фильтр возвращает пустоту, целевой обработчик должен принять все аргументы, не переданные фильтру. Аргументы не переупорядочиваются, и возвращаемое фильтром значение заменяет (по порядку) всю подпоследовательность аргументов, изначально переданных адаптеру.

Типы аргументов (если таковые имеются) фильтра заменяют ноль или один тип аргумента целевого обработчика, в позиции 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 потребляет один аргумент и генерирует непустое возвращаемое значение, то collectArguments(mh, N, coll) эквивалентно filterArguments(mh, N, coll). Другие эквивалентности возможны, но потребуют перестановки аргументов.

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

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

filterReturnValue

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

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

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

Пример:

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 типы параметров целевого обработчика должны точно совпадать с типами параметров комбинирующего обработчика.

Если у комбинирующего обработчика пустое возвращаемое значение, результат не будет вставлен, и первые 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 не пустой и не совпадает с первым типом аргумента целевого обработчика, или если начальные 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.
C момента:
9
См. также:
  • foldArguments(MethodHandle, MethodHandle)

guardWithTest

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

Вот псевдокод для результирующего адаптера. В коде 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

Цикл

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(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>). Более конкретно, мы будем использовать обозначение (V*) для выражения произвольного префикса полного последовательности (V...) (и аналогично для (v*), (A*), (a*)). В этом обозначении общий вид списка параметров функции init — (A*), а общий вид списка параметров функции, не являющейся функцией init, — (V*) или (V... A*).

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

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

Шаг 0: Определение структуры клаузы.

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

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

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

Шаг 1В: Определение параметров цикла (A...).

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

Шаг 1С: Определение типа возврата цикла.

  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. Все функции инициализации имеют общий список типов параметров (A...), который также будет иметь конечная обработка цикла.
  3. Все функции завершения имеют общий тип возвращаемого значения R, который также будет иметь конечная обработка цикла.
  4. Все функции, не являющиеся функциями инициализации, имеют общий список типов параметров (V... A...), содержащий (не-void) переменные итерации V, за которыми следуют параметры цикла.
  5. Каждая пара функций инициализации и шага согласуется в своём типе возвращаемого значения V.
  6. Каждая функция, не являющаяся функцией инициализации, сможет наблюдать текущие значения (v...) всех переменных итерации.
  7. Каждая функция сможет наблюдать входные значения (a...) всех параметров цикла.

Пример. Вследствие шага 1А выше, комбинатор 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...) были получены из функций шага, что естественно, если основная вычислительная работа цикла происходит в шагах. Для некоторых циклов основная вычислительная нагрузка может приходиться на функции предикатов, и поэтому функции предикатов могут нуждаться в принятии значений параметров цикла. Для циклов со сложной логикой выхода функции завершения могут нуждаться в принятии параметров цикла, и то же самое относится к циклам со сложной логикой входа, где функции инициализации потребуют дополнительных параметров. По этим причинам правила определения этих параметров максимально симметричны по всем частям предложений. В общем случае параметры цикла функционируют как общие неизменяемые значения в рамках всего цикла, а переменные итерации — как общие изменяемые значения, или (если нет функции шага) как временные локальные неизменяемые значения цикла.

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

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

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

  • Хотя каждая функция шага получит текущие значения всех переменных цикла, иногда функции шага требуется только наблюдать текущее значение собственной переменной. В этом случае функция шага может потребовать явно отбросить все предыдущие переменные цикла. Для этого потребуется указать их типы в выражении, подобном dropArguments(step, 0, V0.class, ...).
  • Переменные цикла не обязательно должны изменяться; они могут быть неизменяемыми в цикле. Предложение может создать неизменяемую переменную цикла с помощью подходящей функции инициализации без функции шага, предиката или завершения. Это может быть полезно для «подключения» входного аргумента цикла к функции шага или предиката соседней переменной цикла.
  • Если некоторые из функций предложения являются виртуальными методами для экземпляра, сам экземпляр удобно поместить в начальную неизменяемую переменную цикла, используя начальное предложение, подобное 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 - массив массивов (4-кортежей) MethodHandle, соответствующих описанным выше правилам.
Возвращаемое значение:
обработчик метода, воплощающий поведение цикла, как определено аргументами.
Исключения:
IllegalArgumentException - в случае нарушения любого из описанных выше ограничений.
Дата добавления:
9
См. также:
  • whileLoop(MethodHandle, MethodHandle, MethodHandle)
  • doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
  • countedLoop(MethodHandle, MethodHandle, MethodHandle)
  • iteratedLoop(MethodHandle, MethodHandle, MethodHandle)

Цикл while

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.
C момента:
9
См. также:
  • loop(MethodHandle[][])
  • doWhileLoop(MethodHandle, MethodHandle, MethodHandle)

Цикл do-while

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.
C момента:
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 обработчика. Значение, отличное от void, возвращаемое из тела (типа V), обновляет ведущую переменную итерации. Результатом выполнения цикла обработчика будет конечное значение 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, то присутствует ведущая переменная итерации этого типа. Эта переменная инициализируется с помощью необязательного обработчика init или значения по умолчанию типа V, если такой обработчик отсутствует null.

На каждой итерации переменные итерации передаются в вызов обработчика body. Значение, отличное от void, возвращённое из тела (типа V), обновляет ведущую переменную итерации. Результатом выполнения обработчика цикла будет итоговое значение 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 — обработчик, возвращающий начальное значение счётчика цикла, который должен быть int. См. выше для других ограничений.
end — обработчик, возвращающий конечное значение счётчика цикла (цикл выполняется до 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, если этот обработчик отсутствует.

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

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

  • 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, или, если он сгенерирует исключение, нулевое, или 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 сгенерирует. Объявление более узкого типа может привести к генерации исключения ClassCastException обработчиком try-finally, если тип исключения, сгенерированного target, не может быть приведён к первому типу параметра cleanup. Обратите внимание, что различные типы исключений VirtualMachineError, LinkageError и RuntimeException могут в принципе генерироваться практически любым Java-кодом, и блок finally, который ловит (скажем) только IOException, скроет любые другие под ClassCastException.

Parameters:
target - обработчик, чьё выполнение должно быть обернуто в блок try.
cleanup - обработчик, который вызывается в блоке finally.
Returns:
обработчик метода, воплощающий блок try-finally, составленный из двух аргументов.
Throws:
NullPointerException - если какой-либо аргумент равен null
IllegalArgumentException - если cleanup не принимает необходимые ведущие аргументы или если типы обработчиков методов не совпадают по типам возвращаемых значений и соответствующим хвостовым параметрам
Since:
9
See Also:
  • catchException(MethodHandle, Class, MethodHandle)

tableSwitch

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

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

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

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

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

API Note:
Пример: каждый из случаев отбрасывает значение 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"));
Parameters:
fallback - обработчик падения, вызываемый, когда селектор не находится в диапазоне [0, N).
targets - массив целевых обработчиков методов.
Returns:
обработчик табличного переключения.
Throws:
NullPointerException - если fallback, массив targets или любой элемент массива targets равен null.
IllegalArgumentException - если массив targets пуст, если ведущий параметр обработчика падения или любого из обработчиков целевых методов не является int или если типы обработчика падения и всех обработчиков целевых методов не совпадают.

memorySegmentViewVarHandle

public static VarHandle memorySegmentViewVarHandle(ValueLayoutPREVIEW layout)
memorySegmentViewVarHandle является предварительным API платформы Java.
Программы могут использовать memorySegmentViewVarHandle только при включенных предварительных функциях.
Предварительные функции могут быть удалены в будущих версиях или обновлены до постоянных функций платформы Java.
Создаёт объект varHandle, который может использоваться для обращений к сегменту памятиPREVIEW по заданному смещению в байтах, используя предоставленный макет значения.

Предоставленный макет определяет тип носителяPREVIEW, размер в байтахPREVIEW, выравнивание в байтахPREVIEW и порядок байтовPREVIEW, связанные с возвращаемым varHandle.

Список типов координат, связанных с возвращаемым varHandle, равен (MemorySegment, long), где тип координаты long соответствует смещению в байтах в указанный сегмент памяти. Таким образом, возвращаемый varHandle обращается к байтам по смещению в заданном сегменте памяти, собирая байты в значение типа varHandle или извлекая из него байты. Кроме того, операция доступа будет учитывать порядок следования байтов (endianness) и ограничения на выравнивание, выраженные в предоставленном макете.

В качестве примера рассмотрим макет памяти, представленный экземпляром GroupLayoutPREVIEW, созданным следующим образом:

    GroupLayout seq = java.lang.foreign.MemoryLayout.structLayout(
            MemoryLayout.paddingLayout(4),
            ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
    );
Для доступа к элементу с именем value можно создать varHandle для просмотра сегмента памяти следующим образом:
    VarHandle handle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); //(MemorySegment, long) -> int
    handle = MethodHandles.insertCoordinates(handle, 1, 4); //(MemorySegment) -> int
Примечание API:
Возвращаемый varHandle имеет определённые ограничения режима доступа, общие для всех varHandle, относящихся к сегменту памяти. VarHandle для просмотра сегмента памяти связан с размером доступа S и ограничением на выравнивание B (оба выражены в байтах). Мы говорим, что операция доступа к памяти полностью выровнена, если она выполняется по адресу памяти A, совместимому с обоих ограничениями на выравнивание S и B. Если доступ полностью выровнен, то поддерживаются следующие режимы доступа, и гарантируется поддержка атомарного доступа:
  • режимы чтения/записи для всех T, за исключением режимов доступа get и set для long и double на 32-битных платформах.
  • атомарные режимы обновления для int, long, float, double или MemorySegmentPREVIEW. (Будущие основные версии платформы JDK могут поддерживать дополнительные типы для некоторых в настоящее время неподдерживаемых режимов доступа).
  • численные атомарные режимы обновления для int, long и MemorySegmentPREVIEW. (Будущие основные версии платформы JDK могут поддерживать дополнительные числовые типы для некоторых в настоящее время неподдерживаемых режимов доступа).
  • битовые атомарные режимы обновления для int, long и MemorySegmentPREVIEW. (Будущие основные версии платформы JDK могут поддерживать дополнительные числовые типы для некоторых в настоящее время неподдерживаемых режимов доступа).
Если T является float, double или MemorySegmentPREVIEW, то атомарные режимы обновления сравнивают значения, используя их битовое представление (см. Float.floatToRawIntBits(float), Double.doubleToRawLongBits(double) и MemorySegment.address()PREVIEW соответственно).

В противном случае операция доступа к памяти частично выровнена, если она выполняется по адресу памяти A, совместимому только с ограничением на выравнивание B; в таких случаях доступ к чему-либо, кроме режимов доступа get и set, приведёт к исключению IllegalStateException. Если доступ частично выровнен, атомарный доступ гарантируется только относительно наибольшей степени двойки, которая делит НОД (НОК) A и S.

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

Наконец, если T равно MemorySegment, все режимы записи выбрасывают IllegalArgumentException, если записываемое значение не является нативнымPREVIEW сегментом памяти.

Параметры:
layout - макет значения, для которого требуется получить обработчик доступа к памяти.
Возвращает:
новый обработчик varHandle для просмотра сегмента памяти.
Исключения:
NullPointerException - если layout равен null.
С:
19
См. также:
  • MemoryLayout.varHandle(MemoryLayout.PathElement...)PREVIEW

filterValue

public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
filterValue является предварительным API платформы Java.
Программы могут использовать filterValue только при включенных предварительных функциях.
Предварительные функции могут быть удалены в будущих версиях или обновлены до постоянных функций платформы Java.
Изменяет целевой varHandle, предварительно обрабатывая входные и выходные значения с помощью пары функций фильтрации.

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

Для того, чтобы функции фильтров преобразования в/из упакованный тип были корректны, их типы должны иметь вид (A... , S) -> T и (A... , T) -> S соответственно, где T - тип целевого varHandle. В этом случае результирующий varHandle будет иметь тип S и будет содержать дополнительные координаты A... (которые будут добавлены к координатам целевого varHandle).

Если функции фильтров преобразования в/из упакованный тип выбрасывают какие-либо проверенные исключения при вызове, результирующий varHandle будет выбрасывать исключение IllegalStateException.

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

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

filterCoordinates

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

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

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

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

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

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

insertCoordinates

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

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

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

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

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

permuteCoordinates

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

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

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

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

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

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

collectCoordinates

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

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

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

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

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

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

dropCoordinates

public static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes)
dropCoordinates — это предварительный API платформы Java.
Программы могут использовать dropCoordinates только при включенных предварительных функциях.
Предварительные функции могут быть удалены в будущих выпусках или обновлены до постоянных функций платформы Java.
Возвращает обработчик переменной, который отбросит некоторые фиктивные координаты перед делегированием целевому обработчику переменной. В результате, у результирующего обработчика переменной будет больше типов координат, чем у целевого обработчика переменной.

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

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

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

© 1993, 2023, 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/21/docs/api/java.base/java/lang/invoke/MethodHandles.html

Spec-Zone.ru

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