Spec-Zone.ru › OpenJDK 24

Класс 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)
Адаптирует целевой VarHandle, предварительно обрабатывая подпоследовательность его координат с помощью фильтра (обработчик метода).
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)
Возвращает VarHandle, который отбросит некоторые фиктивные координаты перед делегированием целевому VarHandle.
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)
Адаптирует целевой VarHandle, предварительно обрабатывая входящие значения координат с использованием унарных функций фильтра.
static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter)
Адаптирует целевой обработчик метода, послеобрабатывая его возвращаемое значение (если таковое имеется) с помощью фильтра (другой обработчик метода).
static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
Адаптирует целевой VarHandle, предварительно обрабатывая входящие и исходящие значения с помощью пары функций фильтра.
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)
Предоставляет целевому VarHandle один или несколько связанных координат до вызова VarHandle.
static MethodHandle invoker(MethodType type)
Создаёт специальный обработчик метода вызова, который может быть использован для вызова любого совместимого обработчика метода с данным типом, как если бы он был вызван с помощью invoke.
static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body)
Создаёт цикл, который перебирает значения, созданные Iterator<T>.
static MethodHandles.Lookup lookup()
Возвращает lookup object с полными возможностями эмуляции всех поддерживаемых байткодовых действий вызывающей стороны.
static MethodHandle loop(MethodHandle[]... clauses)
Создаёт обработчик метода, представляющий цикл с несколькими переменными цикла, которые обновляются и проверяются на каждой итерации.
static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder)
Создаёт обработчик метода, который адаптирует последовательность вызова данного обработчика метода к новому типу путём переупорядочивания аргументов.
static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder)
Предоставляет VarHandle, который адаптирует значения координат целевого VarHandle, переупорядочивая их так, чтобы новые координаты соответствовали предоставленным.
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)
Создаёт специальный обработчик метода-вызывателя (invoker method handle), который можно использовать для вызова метода с полиморфной подписью в режиме доступа (access mode) к любому VarHandle, тип связанного режима доступа которого совместим с заданным типом.
static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type)
Создаёт специальный обработчик метода-вызывателя (invoker method handle), который можно использовать для вызова метода с полиморфной подписью в режиме доступа (access mode) к любому VarHandle, тип связанного режима доступа которого совместим с заданным типом.
static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body)
Строит цикл while из инициализатора, тела и предиката.
static MethodHandle zero(Class<?> type)
Создаёт константный обработчик метода (constant method handle) требуемого типа возврата, который каждый раз при вызове возвращает значение по умолчанию для этого типа.

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

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

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

lookup

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

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

Returns:
объект lookup для вызывающей стороны этого метода, с оригинальным и полным доступом с привилегиями.
Throws:
IllegalCallerException - если на стеке нет фрейма вызывающей стороны.

publicLookup

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

По соглашению, классом lookup этого объекта lookup будет Object.

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

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

Returns:
объект lookup с минимальным уровнем доверия

privateLookupIn

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

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

  • Объект 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 Note:
Объект Lookup, возвращённый этим методом, разрешено определять классы в пакете runtime класса targetClass. Необходимо проявлять крайнюю осторожность при открытии пакета для другого модуля, так как такие определённые классы имеют такие же права доступа с привилегиями, как и другие члены модуля targetClass.
Parameters:
targetClass - целевой класс
caller - объект lookup вызывающей стороны
Returns:
объект lookup для целевого класса с приватным доступом
Throws:
IllegalArgumentException - если targetClass является примитивным типом, пустым или массивом
NullPointerException - если targetClass или caller являются null
IllegalAccessException - если любая из других проверок доступа указанных выше не пройдена
Since:
9
See Also:
  • MethodHandles.Lookup.dropLookupMode(int)
  • Межмодульные lookup

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

classDataAt

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

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

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

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

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

reflectAs

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

arrayConstructor

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

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

Параметры:
arrayClass - тип массива
Возвращаемое значение:
обработчик метода, который может создавать массивы данного типа
Исключения:
NullPointerException - если аргумент является null
IllegalArgumentException - если arrayClass не является типом массива
См. Спецификацию виртуальной машины Java:
6.5 anewarray Instruction
С версии:
9
См. также:
  • 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 не является типом массива
See Java Virtual Machine Specification:
6.5 arraylength Инструкция
Since:
9

arrayElementGetter

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

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

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

arrayElementSetter

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

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

Parameters:
arrayClass - класс массива
Returns:
обработчик метода, который может сохранять значения в массив
Throws:
NullPointerException - если аргумент равен null
IllegalArgumentException - если arrayClass не является типом массива
See Java Virtual Machine Specification:
6.5 aastore Инструкция

arrayElementVarHandle

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

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

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

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

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

API 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.

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

API Note:
Если требуются режимы доступа, отличные от обычных, клиенты должны рассмотреть использование вне-кучной памяти через прямые буферы байтов или вне-кучные сегменты памяти, или сегменты памяти, поддерживаемые long[], для которых могут быть сделаны более сильные гарантии выравнивания.
Parameters:
viewArrayClass - класс массива-представления, с компонентным типом типа T
byteOrder - порядок байтов элементов массива-представления, как хранятся в базовом массиве byte
Returns:
VarHandle, предоставляющий доступ к элементам массива byte[], рассматриваемого как элементы, соответствующие компонентному типу класса массива-представления
Throws:
NullPointerException - если viewArrayClass или byteOrder равны null
IllegalArgumentException - если viewArrayClass не является типом массива
UnsupportedOperationException - если компонентный тип viewArrayClass не поддерживается как тип переменной
Since:
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.

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

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

вызыватель

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

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

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

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

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

Этот метод не генерирует никаких исключений, связанных с отражением.

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

varHandleExactInvoker

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

varHandleInvoker

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

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

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

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

explicitCastArguments

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

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

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

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

permuteArguments

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

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

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

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

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

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

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

константа

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

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

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

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

тождество

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

ноль

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

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

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

пустой

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

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

Примечание API:
Исходя из предиката и целевого объекта, можно создать полезную конструкцию "если-то" как guardWithTest(pred, target, empty(target.type()).
Параметры:
type - тип желаемого обработчика метода
Возвращает:
константный обработчик метода заданного типа, возвращающий значение по умолчанию для заданного возвращаемого типа
Исключения:
NullPointerException - если аргумент равен null
С:
9
См. также:
  • zero(java.lang.Class<?>)
  • constant(java.lang.Class<?>, java.lang.Object)

вставитьАргументы

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

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

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

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

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

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

удалитьАргументы

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

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

Пример:

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

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

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

удалитьАргументы

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

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

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

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

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

dropArgumentsToMatch

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

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

В более формальных терминах, предположим два списка типов:

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

dropReturn

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

filterArguments

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

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

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

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

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

Пример:

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

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

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

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

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

collectArguments

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

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

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

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

Пример:

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

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

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

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

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

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

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

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

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

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

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

Параметры:
target - метод-обработчик, который вызывается после фильтрации подпоследовательности аргументов
pos - позиция первого аргумента адаптера, который передаётся фильтру, и/или аргумент целевого метода, получающий результат фильтра
filter - метод-обработчик, вызываемый для подпоследовательности аргументов
Возвращает:
метод-обработчик, который включает в себя указанную логику фильтрации подпоследовательности аргументов
Исключения:
NullPointerException - если любой из аргументов равен null
IllegalArgumentException - если тип возвращаемого значения filter отличен от void и не совпадает с типом аргумента pos целевого метода, или если pos не находится в диапазоне от 0 до арности целевого метода включительно, или если тип результирующего метода-обработчика будет иметь слишком много параметров
См. также:
  • foldArguments(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)
Адаптирует целевой метод-обработчик, послеобрабатывая его возвращаемое значение (если таковое имеется) с помощью фильтра (другой метод-обработчик). Результат фильтра возвращается адаптером.

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

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

Пример:

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

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

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

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

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

foldArguments

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

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

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

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

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

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

Пример:

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

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

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

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

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

foldArguments

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

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

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

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

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

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

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

guardWithTest

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

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

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

catchException

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

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

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

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

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

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

throwException

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

Цикл

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

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

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

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

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

Параметры цикла: Функция клаузы может принимать все значения переменной итерации, на которые она имеет право, а в этом случае она также может принимать дополнительные параметры. Такие дополнительные значения называются параметрами цикла, их типы и значения обозначаются как (A...) и v. Эти значения станут параметрами полученного обработчика цикла, которые будут предоставлены при выполнении цикла. (Поскольку функции 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[][]) должен быть не-null и содержать как минимум один элемент.
  2. Массив клаузы не может содержать null или подмассивы длиной более четырех элементов.
  3. Клаузы длиной менее четырех элементов обрабатываются так, как если бы они были дополнены null элементами до длины четыре. Дополнение происходит путем добавления элементов в массив.
  4. Клаузы со всеми null игнорируются.
  5. Каждая клауза обрабатывается как четверка функций, называемых «init», «step», «pred» и «fini».

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

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

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

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

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

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

Шаг 1D: Проверка других типов.

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

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

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

Шаг 3: Заполнение пропущенных функций.

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

Шаг 4: Заполнение недостающих типов параметров.

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

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

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

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

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

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

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

Рекомендации по использованию.

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

iteratedLoop

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

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

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

В каждой итерации переменные цикла передаются в вызов 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 или нулевые значения.)

Обработчики cleanup и 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, если тип исключения, брошенного 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 или если типы обработчика по умолчанию и всех целевых обработчиков не совпадают.
Since:
17

filterValue

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

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

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

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

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

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

ОбработкаКоординат

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

При вызове, например, 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.
С:
22

ВставкаКоординат

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

При вызове, например, 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.
С:
22

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

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

Заданный массив определяет переупорядочение. Обозначим количество входящих координат как 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.
С:
22

СборКоординат

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

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

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

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

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

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

dropCoordinates

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

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

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

Parameters:
target - дескриптор переменной, к которому будет обращение после отбрасывания фиктивных координат
pos - позиция первой координаты для отбрасывания (ноль для самой левой)
valueTypes - тип(ы) координаты(ы) для отбрасывания
Returns:
адаптированный дескриптор переменной, который отбрасывает некоторые фиктивные координаты перед вызовом целевого дескриптора переменной
Throws:
IllegalArgumentException - если pos не находится в диапазоне от 0 до арности координат целевого дескриптора переменной включительно.
NullPointerException - если любой из аргументов является null или valueTypes содержит null.
Since:
22

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

Spec-Zone.ru

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