Класс MethodHandles

public class MethodHandles
extends Object

Этот класс состоит исключительно из статических методов, которые работают с обработчиками методов или возвращают их. Они делятся на несколько категорий:

С:
1.7

Вложенные классы

Модификатор и тип Класс Описание
static 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 MethodHandle collectArguments​(MethodHandle target, int pos, MethodHandle filter)

Адаптирует целевой обработчик метода путём предварительной обработки подпоследовательности его аргументов с помощью фильтра (другого обработчика метода).

static MethodHandle constant​(Class<?> type, Object value)

Создаёт обработчик метода запрошенного возвращаемого типа, который возвращает заданное констанное значение каждый раз при вызове.

static MethodHandle countedLoop​(MethodHandle iterations, MethodHandle init, MethodHandle body)

Создаёт цикл, который выполняется заданное количество итераций.

static MethodHandle countedLoop​(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body)

Создаёт цикл, который перебирает диапазон чисел.

static MethodHandle doWhileLoop​(MethodHandle init, MethodHandle body, MethodHandle pred)

Создаёт цикл do-while из инициализатора, тела и предиката.

static MethodHandle dropArguments​(MethodHandle target, int pos, Class<?>... valueTypes)

Создаёт обработчик метода, который отбросит некоторые фиктивные аргументы перед вызовом другого указанного целевого обработчика метода.

static MethodHandle dropArguments​(MethodHandle target, int pos, List<Class<?>> valueTypes)

Создаёт обработчик метода, который отбросит некоторые фиктивные аргументы перед вызовом другого указанного целевого обработчика метода.

static MethodHandle dropArgumentsToMatch​(MethodHandle target, int skip, List<Class<?>> newTypes, int pos)

Адаптирует целевой обработчик метода к заданному списку типов параметров.

static 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 MethodHandle filterReturnValue​(MethodHandle target, MethodHandle filter)

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

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 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 MethodHandles.Lookup privateLookupIn​(Class<?> targetClass, MethodHandles.Lookup lookup)

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

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 throwException​(Class<?> returnType, Class<? extends Throwable> exType)

Создаёт обработчик метода, который будет выбрасывать исключения заданного exType.

static MethodHandle tryFinally​(MethodHandle target, MethodHandle cleanup)

Создаёт обработчик метода, который адаптирует target обработчик метода, обернув его в try-finally блок.

static MethodHandle varHandleExactInvoker​(VarHandle.AccessMode accessMode, MethodType type)

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

static MethodHandle varHandleInvoker​(VarHandle.AccessMode accessMode, MethodType type)

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

static MethodHandle whileLoop​(MethodHandle init, MethodHandle pred, MethodHandle body)

Создаёт цикл while из инициализатора, тела и предиката.

static MethodHandle zero​(Class<?> type)

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

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

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

Методы

lookup

public static MethodHandles.Lookup lookup()

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

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

Возвращает:
объект lookup для вызывающего объекта этого метода с доступом к закрытым членам

publicLookup

public static MethodHandles.Lookup publicLookup()

Возвращает lookup object, который имеет минимальный уровень доверия. Lookup имеет режимы PUBLIC и UNCONDITIONAL. Он может использоваться только для создания обработчиков методов для общедоступных членов общедоступных классов в пакетах, которые экспортируются безусловно.

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

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

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

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

privateLookupIn

public static MethodHandles.Lookup privateLookupIn(Class<?> targetClass,
                                                   MethodHandles.Lookup lookup)
                                            throws IllegalAccessException

Возвращает lookup object с полными возможностями эмуляции всех поддерживаемых поведений байткода, включая доступ к закрытым членам, для целевого класса. Этот метод проверяет, разрешено ли вызывающему объекту, указанному как объект Lookup, выполнять глубокое рефлексивное отражение целевого класса. Если m1 — модуль, содержащий lookup class, а m2 — модуль, содержащий целевой класс, то эта проверка гарантирует, что

  • m1 reads m2.
  • m2 opens пакет, содержащий целевой класс, как минимум до m1.
  • Lookup имеет режим MODULE.

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

Примечание API:
Режим lookup MODULE служит для аутентификации того, что объект lookup был создан кодом в модуле вызывающего объекта (или получен из объекта lookup, первоначально созданного вызывающим объектом). Объект lookup с режимом MODULE может быть передан надёжным сторонам без раскрытия PRIVATE и PACKAGE доступа к вызывающему объекту.
Параметры:
targetClass - целевой класс
lookup - вызывающий объект lookup
Возвращает:
объект lookup для целевого класса с доступом к закрытым членам
Исключения:
IllegalArgumentException - если targetClass является примитивным типом или классом массива
NullPointerException - если targetClass или caller является null
IllegalAccessException - если проверка доступа, описанная выше, завершается неудачно
SecurityException - если запрещено менеджером безопасности
С:
9
См. также:
MethodHandles.Lookup.dropLookupMode(int)

reflectAs

public static <T extends Member> T reflectAs(Class<T> expected,
                                             MethodHandle target)

Выполняет непроверенное "раскрытие" прямого обработчика метода. Результат аналогичен тому, как если бы пользователь получил объект lookup, достаточно способный для раскрытия целевого обработчика метода, вызвав Lookup.revealDirect на целевом объекте для получения его символической ссылки, а затем вызвав MethodHandleInfo.reflectAs для преобразования символической ссылки в член.

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

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

arrayConstructor

public static MethodHandle arrayConstructor(Class<?> arrayClass)
                                     throws IllegalArgumentException

Создаёт обработчик метода для создания массивов заданного типа, как если бы был использован anewarray байткод. Тип возвращаемого обработчика метода будет типом массива. Тип единственного аргумента будет int, что определяет размер массива.

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

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

arrayLength

public static MethodHandle arrayLength(Class<?> arrayClass)
                                throws IllegalArgumentException

Создаёт обработчик метода для возвращения длины массива, как если бы был использован arraylength байткод. Тип обработчика метода будет иметь int в качестве типа возвращаемого значения, а единственный аргумент будет типом массива.

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

Параметры:
arrayClass - тип массива
Возвращает:
обработчик метода, который может получить длину массива заданного типа
Исключения:
NullPointerException - если аргумент является null
IllegalArgumentException - если arrayClass не является типом массива
С:
9

arrayElementGetter

public static MethodHandle arrayElementGetter(Class<?> arrayClass)
                                       throws IllegalArgumentException

Создаёт обработчик метода для чтения элементов массива, как если бы был использован aaload байткод. Тип возвращаемого значения обработчика метода будет типом элемента массива. Первый аргумент будет типом массива, а второй — int.

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

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

arrayElementSetter

public static MethodHandle arrayElementSetter(Class<?> arrayClass)
                                       throws IllegalArgumentException

Создаёт обработчик метода для записи в элементы массива, как если бы был использован astore байткод. Тип возвращаемого значения обработчика метода будет void. Последний аргумент будет типом элемента массива. Первый и второй аргументы будут типом массива и int.

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

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

arrayElementVarHandle

public static VarHandle arrayElementVarHandle(Class<?> arrayClass)
                                       throws IllegalArgumentException

Создаёт VarHandle, предоставляющий доступ к элементам массива типа arrayClass. Тип переменной VarHandle — это компонентный тип arrayClass, а список типов координат — (arrayClass, int), где тип координаты int соответствует аргументу, являющемуся индексом в массиве.

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

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

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

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

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

byteArrayViewVarHandle

public static VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass,
                                               ByteOrder byteOrder)
                                        throws IllegalArgumentException

Создаёт VarHandle, предоставляющий доступ к элементам массива byte[] , рассматриваемого как массив другого примитивного типа, например, int[] или long[]. Тип переменной VarHandle — это компонентный тип viewArrayClass, а список типов координат — (byte[], int), где тип координаты int соответствует аргументу, являющемуся индексом в массиве byte[] . Возвращаемый VarHandle обращается к байтам по индексу в массиве byte[], комбинируя байты в значение компонентного типа viewArrayClass в соответствии с заданной направленностью.

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

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

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

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

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

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

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

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

byteBufferViewVarHandle

public static VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass,
                                                ByteOrder byteOrder)
                                         throws IllegalArgumentException

Создаёт VarHandle, предоставляющий доступ к элементам ByteBuffer, рассматриваемым как массив элементов другого примитивного типа, отличного от byte, такого как int[] или long[]. Тип переменной VarHandle — это компонентный тип viewArrayClass, а список типов координат — (ByteBuffer, int), где тип координаты int соответствует аргументу, являющемуся индексом в массиве byte[]. Возвращаемый VarHandle обращается к байтам по индексу в ByteBuffer, комбинируя байты с/из значения компонентного типа viewArrayClass в соответствии с заданным порядком байтов.

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

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

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

Доступ к байтам по индексу может быть выровнен или не выровнен по отношению к основному адресу памяти T, например, связанному с 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;
Этот метод не генерирует исключений Reflection или Security.
Параметры:
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 Core Reflection. Попытка вызвать java.lang.reflect.Method.invoke на объявленный invokeExact или invoke метод вызовет UnsupportedOperationException.)

Этот метод не генерирует исключений Reflection или Security.

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

invoker

public static MethodHandle invoker(MethodType type)

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

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

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

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

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

Этот метод не генерирует исключений Reflection или Security.

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

varHandleExactInvoker

public static MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode,
                                                 MethodType type)

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

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

varHandleInvoker

public static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode,
                                            MethodType type)

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

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

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

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

explicitCastArguments

public static MethodHandle explicitCastArguments(MethodHandle target,
                                                 MethodType newType)

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

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

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

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

permuteArguments

public static MethodHandle permuteArguments(MethodHandle target,
                                            MethodType newType,
                                            int... reorder)

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

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

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

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

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

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

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

constant

public static MethodHandle constant(Class<?> type,
                                    Object value)

Создаёт дескриптор метода требуемого типа, который каждый раз при вызове возвращает заданное значение константы.

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

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

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

identity

public static MethodHandle identity(Class<?> type)

Создаёт дескриптор метода, который возвращает свой единственный аргумент при вызове.

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

zero

public static MethodHandle zero(Class<?> type)

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

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

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

empty

public static MethodHandle empty(MethodType type)

Создаёт дескриптор метода заданного типа, который игнорирует любые аргументы, ничего не делает и возвращает подходящее значение по умолчанию в зависимости от типа возврата. То есть, он возвращает примитивное значение нуль, null, или void.

Возвращаемый дескриптор метода эквивалентен 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)

insertArguments

public static MethodHandle insertArguments(MethodHandle target,
                                           int pos,
                                           Object... values)

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

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

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

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

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

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

dropArguments

public static MethodHandle dropArguments(MethodHandle target,
                                         int pos,
                                         List<Class<?>> valueTypes)

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

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

Пример:

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

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

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

dropArguments

public static MethodHandle dropArguments(MethodHandle target,
                                         int pos,
                                         Class<?>... valueTypes)

Создаёт обработчик метода, который отбрасывает некоторые фиктивные аргументы перед вызовом другого заданного целевого обработчика методов. Тип нового обработчика методов будет таким же, как тип целевого объекта, за исключением того, что он также будет содержать типы фиктивных аргументов в определённой позиции.

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

Примечание API:
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 — обработчик метода, который будет вызван после отбрасывания аргументов
valueTypes — тип(ы) аргумента(ов) для отбрасывания
pos — позиция первого аргумента для отбрасывания (ноль для самого левого)
Возвращает:
обработчик метода, который отбрасывает аргументы заданных типов перед вызовом исходного обработчика метода
Исключение:
NullPointerException — если целевой объект равен null, или если массив valueTypes или любой из его элементов равен null
IllegalArgumentException — если любой элемент valueTypes равен void.class, или если pos отрицательно или больше, чем арность целевого объекта, или если тип нового обработчика метода будет иметь слишком много параметров

dropArgumentsToMatch

public static MethodHandle dropArgumentsToMatch(MethodHandle target,
                                                int skip,
                                                List<Class<?>> newTypes,
                                                int pos)

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

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

Более формально, предположим следующие два списка типов:

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

filterArguments

public static MethodHandle filterArguments(MethodHandle target,
                                           int pos,
                                           MethodHandle... filters)

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

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

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

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

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

Пример:

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

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

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

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

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

collectArguments

public static MethodHandle collectArguments(MethodHandle target,
                                            int pos,
                                            MethodHandle filter)

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

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

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

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

filterReturnValue

public static MethodHandle filterReturnValue(MethodHandle target,
                                             MethodHandle filter)

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

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

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

Пример:

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

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

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

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

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

foldArguments

public static MethodHandle foldArguments(MethodHandle target,
                                         MethodHandle combiner)

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

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

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

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

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

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

Пример:

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

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

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

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

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

foldArguments

public static MethodHandle foldArguments(MethodHandle target,
                                         int pos,
                                         MethodHandle combiner)

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

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

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

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

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

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

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

guardWithTest

public static MethodHandle guardWithTest(MethodHandle test,
                                         MethodHandle target,
                                         MethodHandle fallback)

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

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

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

catchException

public static MethodHandle catchException(MethodHandle target,
                                          Class<? extends Throwable> exType,
                                          MethodHandle handler)

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

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

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

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

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

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

throwException

public static MethodHandle throwException(Class<?> returnType,
                                          Class<? extends Throwable> exType)

Создает обработчик метода, который будет выбрасывать исключения заданного exType. Обработчик метода будет принимать один аргумент типа exType, и немедленно выбросит его как исключение. Тип метода номинально указывает на возврат returnType. Тип возврата может быть любым удобным: это не имеет значения для поведения обработчика метода, так как он никогда не вернётся нормально.

Параметры:
returnType - тип возврата желаемого обработчика метода
exType - тип параметра желаемого обработчика метода
Возвращает:
обработчик метода, который может выбросить заданные исключения
Использует исключения:
NullPointerException - если любой из аргументов равен null

loop

public static MethodHandle loop(MethodHandle[]... clauses)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Итоговые замечания.

  1. После этих шагов все фразы были скорректированы путем добавления пропущенных функций и аргументов.
  2. Все функции 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 — это количество типов, отличных от void 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. Затем функции шага и pred выполняются в порядке фраз (шаг перед pred), пока функция pred не вернет значение false.
  5. Результат функции шага, не являющейся void, используется для обновления соответствующего значения в последовательности (v...) переменных цикла. Обновленное значение немедленно видно всем последующим вызовам функций.
  6. Если функция pred возвращает значение false, вызывается соответствующая функция fini, а возвращаемое значение (типа R) возвращается из цикла в целом.
  7. Если все функции pred всегда возвращают 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)

whileLoop

public static MethodHandle whileLoop(MethodHandle init,
                                     MethodHandle pred,
                                     MethodHandle body)

Создает цикл while из инициализатора, тела и предиката. Это обертка для удобства использования общего комбинатора цикла.

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

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

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

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

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

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

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

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

doWhileLoop

public static MethodHandle doWhileLoop(MethodHandle init,
                                       MethodHandle body,
                                       MethodHandle pred)

Создаёт цикл do-while из инициализации, тела и предиката. Это обёртка для общего комбинатора циклов.

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

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

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

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

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

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

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

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

countedLoop

public static MethodHandle countedLoop(MethodHandle iterations,
                                       MethodHandle init,
                                       MethodHandle body)

Создаёт цикл, который выполняется заданное количество итераций. Это обёртка для общего комбинатора циклов.

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

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

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

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

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

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

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

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

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

countedLoop

public static MethodHandle countedLoop(MethodHandle start,
                                       MethodHandle end,
                                       MethodHandle init,
                                       MethodHandle body)

Создаёт цикл, перебирающий диапазон чисел. Это удобная оболочка для обобщённого комбинирующего цикла.

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

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

На каждой итерации переменные итерации передаются в вызов обработчика 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 - обработчик, не являющийся null, для возврата начального значения счётчика цикла, которое должно быть int. См. выше для других ограничений.
end - обработчик, не являющийся null, для возврата конечного значения счётчика цикла (цикл будет выполняться до end-1). Тип результата должен быть int. См. выше для других ограничений.
init - необязательный инициализатор, предоставляющий начальное значение переменной цикла. Может быть null, подразумевая значение по умолчанию. См. выше для других ограничений.
body - тело цикла, которое не может быть null. Оно управляет параметрами цикла и типом результата в стандартном случае (см. подробности выше). Оно должно принимать свой собственный тип возврата (если не void) плюс параметр int (для счётчика) и может принимать любое количество дополнительных типов. См. выше для других ограничений.
Возвращает:
обработчик метода, представляющий цикл.
Исключения:
NullPointerException - если любой из обработчиков start, end, или body является null.
IllegalArgumentException - если какой-либо аргумент нарушает сформулированные выше правила.
С тех пор как:
9
См. также:
countedLoop(MethodHandle, MethodHandle, MethodHandle)

iteratedLoop

public static MethodHandle iteratedLoop(MethodHandle iterator,
                                        MethodHandle init,
                                        MethodHandle body)

Создаёт цикл, который перебирает значения, полученные от Iterator<T>. Это удобная обёртка для обобщённого комбинатора циклов.

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

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

В каждой итерации значения переменных цикла передаются в вызов body хэндла. Значение, отличное от 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, или, если он сгенерирует исключение, значение null, ноль или false необходимого типа, которое используется в качестве заполнителя. Второй аргумент отсутствует, если обработчик target имеет тип возвращаемого значения void. (Обратите внимание, что, за исключением преобразований типов аргументов, комбинирующие методы представляют значения void в списках параметров, опуская соответствующие парадоксальные аргументы, а не вставляя null или нулевые значения.)

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

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

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

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

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

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

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

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

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

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

Spec-Zone .ru
спецификации, руководства, описания, API