Класс MethodHandles
- java.lang.Object
-
- java.lang.invoke.MethodHandles
public class MethodHandles extends Object
Этот класс состоит исключительно из статических методов, которые работают с обработчиками методов или возвращают их. Они делятся на несколько категорий:
- Методы поиска, которые помогают создавать обработчики методов для методов и полей.
- Комбинаторные методы, которые объединяют или преобразуют существующие обработчики методов в новые.
- Другие фабричные методы для создания обработчиков методов, которые эмулируют другие общие операции JVM или шаблоны управления потоком.
- С:
- 1.7
Вложенные классы
| Модификатор и тип | Класс | Описание |
|---|---|---|
static class | MethodHandles.Lookup | Объект поиска — это фабрика для создания обработчиков методов, когда для создания требуется проверка доступа. |
Методы
| Модификатор и тип | Метод | Описание |
|---|---|---|
static MethodHandle | arrayConstructor(Class<?> arrayClass) | Создаёт обработчик метода, создающего массивы желаемого типа, как если бы с помощью байткода |
static MethodHandle | arrayElementGetter(Class<?> arrayClass) | Создаёт обработчик метода, предоставляющий доступ для чтения к элементам массива, как если бы с помощью байткода |
static MethodHandle | arrayElementSetter(Class<?> arrayClass) | Создаёт обработчик метода, предоставляющий доступ для записи к элементам массива, как если бы с помощью байткода |
static VarHandle | arrayElementVarHandle(Class<?> arrayClass) | Создаёт VarHandle, предоставляющий доступ к элементам массива типа |
static MethodHandle | arrayLength(Class<?> arrayClass) | Создаёт обработчик метода, возвращающий длину массива, как если бы с помощью байткода |
static VarHandle | byteArrayViewVarHandle(Class<?> viewArrayClass,
ByteOrder byteOrder) | Создаёт VarHandle, предоставляющий доступ к элементам массива |
static VarHandle | byteBufferViewVarHandle(Class<?> viewArrayClass,
ByteOrder byteOrder) | Создаёт VarHandle, предоставляющий доступ к элементам массива |
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) | Создаёт цикл |
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) | Создаёт специальный обработчик метода вызова, который может использоваться для вызова любого обработчика метода данного типа, как если бы с помощью |
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) | Создаёт специальный обработчик метода вызова, который может использоваться для вызова любого обработчика метода, совместимого с заданным типом, как если бы с помощью |
static MethodHandle | iteratedLoop(MethodHandle iterator,
MethodHandle init,
MethodHandle body) | Создаёт цикл, который перебирает значения, полученные от |
static MethodHandles.Lookup | lookup() | Возвращает |
static MethodHandle | loop(MethodHandle[]... clauses) | Создаёт обработчик метода, представляющий цикл с несколькими переменными цикла, которые обновляются и проверяются на каждой итерации. |
static MethodHandle | permuteArguments(MethodHandle target,
MethodType newType,
int... reorder) | Создаёт обработчик метода, который адаптирует последовательность вызова данного обработчика метода к новому типу, переупорядочивая аргументы. |
static MethodHandles.Lookup | privateLookupIn(Class<?> targetClass,
MethodHandles.Lookup lookup) | Возвращает |
static MethodHandles.Lookup | publicLookup() | Возвращает |
static <T extends Member> | reflectAs(Class<T> expected,
MethodHandle target) | Выполняет неконтролируемое "взлом" прямого обработчика метода. |
static MethodHandle | spreadInvoker(MethodType type,
int leadingArgCount) | Создаёт обработчик метода, который вызовет любой обработчик метода данного |
static MethodHandle | throwException(Class<?> returnType,
Class<? extends Throwable> exType) | Создаёт обработчик метода, который будет выбрасывать исключения заданного |
static MethodHandle | tryFinally(MethodHandle target,
MethodHandle cleanup) | Создаёт обработчик метода, который адаптирует |
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) | Создаёт цикл |
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 — модуль, содержащий целевой класс, то эта проверка гарантирует, что
-
m1readsm2. -
m2opensпакет, содержащий целевой класс, как минимум до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 или массивfiltersnull -
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: Определение структуры условия.
- Массив условий (типа
MethodHandle[][]) должен быть непустым и содержать по крайней мере один элемент. - Массив условий не может содержать
nullили подмассивы длиной более четырёх элементов. - Условия длиной менее четырёх элементов обрабатываются так, как будто они заполнены
nullэлементами до длины четыре. Заполнение происходит путём добавления элементов в массив. - Условия, у которых все
nullпусты, игнорируются. - Каждое условие обрабатывается как четвёрка функций, называемых "init", "step", "pred" и "fini".
Шаг 1А: Определение типов переменных итерации (V...).
- Тип переменной итерации для каждого условия определяется с помощью типов возврата функций init и step этого условия.
- Если обе функции отсутствуют, переменная итерации для соответствующего условия отсутствует (
voidиспользуется в качестве типа для обозначения этого). Если одна из них отсутствует, тип возврата другой определяет тип переменной итерации условия. Если обе функции присутствуют, общий тип возврата (они должны быть идентичны) определяет тип переменной итерации условия. - Сформируйте список типов возврата (в порядке условий), исключив все вхождения
void. - Этот список типов называется "типами переменных итерации" (
(V...)).
Шаг 1Б: Определение параметров цикла (A...).
- Просмотрите и соберите списки параметров функций init (они имеют вид
(A*)). - Просмотрите и соберите суффиксы списков параметров step, pred и fini после удаления типов переменных итерации. (Они должны иметь вид
(V... A*); собирайте только части(A*)). - Не собирайте суффиксы из списков параметров step, pred и fini, которые не начинаются со всех типов переменных итерации. (Эти типы будут проверены на шаге 2 вместе со всеми типами функций условий.)
- Опущенные функции условий игнорируются. (Равносильно, они считаются имеющими пустые списки параметров.)
- Все собранные списки параметров должны быть эффективно идентичными.
- Самый длинный список параметров (который обязательно уникален) называется "внешним списком параметров" (
(A...)). - Если такого списка параметров нет, внешний список параметров принимается за пустую последовательность.
- Объединённый список, состоящий из типов переменных итерации, за которым следуют типы внешних параметров, называется "внутренним списком параметров".
Шаг 1С: Определение типа возврата цикла.
- Просмотрите типы возврата функций fini, игнорируя опущенные функции fini.
- Если функций fini нет, тип возврата цикла —
void. - В противном случае общий тип возврата
Rфункций fini (их типы возврата должны быть идентичны) определяет тип возврата цикла.
Шаг 1D: Проверка других типов.
- Должна быть по крайней мере одна не пропущенная функция pred.
- Каждая не пропущенная функция pred должна иметь тип возврата
boolean.
Шаг 2: Определение списков параметров.
- Список параметров для полученного обработчика цикла будет внешним списком параметров
(A...). - Список параметров для функций init будет скорректирован до внешнего списка параметров. (Обратите внимание, что их списки параметров уже эффективно идентичны этому списку.)
- Список параметров для каждой не пропущенной, не являющейся функцией init (step, pred и fini) функции должен быть эффективно идентичен внутреннему списку параметров
(V... A...).
Шаг 3: Заполнение пропущенных функций.
- Если функция init пропущена, используйте значение по умолчанию для типа переменной итерации условия.
- Если функция step пропущена, используйте тождественную функцию типа переменной итерации условия; вставьте пропущенные аргументы до параметра тождественной функции для не-
voidпеременных итерации предыдущих условий. (Это сделает переменную цикла локальной неизменяемой переменной цикла.) - Если функция pred пропущена, используйте функцию константы
true. (Это позволит циклу продолжать работу, насколько это касается этого условия. Обратите внимание, что в таких случаях соответствующая функция fini недостижима.) - Если функция fini пропущена, используйте значение по умолчанию для типа возврата цикла.
Шаг 4: Заполнение отсутствующих типов параметров.
- На этом этапе каждый список параметров функции init эффективно идентичен внешнему списку параметров
(A...), но некоторые списки могут быть короче. Для каждой функции init с коротким списком параметров заполните конец списка. - На этом этапе каждый список параметров функции, не являющейся функцией init, эффективно идентичен внутреннему списку параметров
(V... A...), но некоторые списки могут быть короче. Для каждой функции, не являющейся функцией init, с коротким списком параметров заполните конец списка. - Списки аргументов дополняются путём удаления неиспользуемых хвостовых аргументов.
Итоговые замечания.
- После этих шагов все фразы были скорректированы путем добавления пропущенных функций и аргументов.
- Все функции init имеют общий список типов параметров
(A...), который также будет иметь конечная обработка цикла. - Все функции fini имеют общий тип возвращаемого значения
R, который также будет иметь конечная обработка цикла. - Все функции, не являющиеся init, имеют общий список типов параметров
(V... A...), включающий переменные итерации (неvoid)V, за которыми следуют параметры цикла. - Каждая пара функций init и step согласуется в своем типе возвращаемого значения
V. - Каждая функция, не являющаяся init, сможет наблюдать текущие значения
(v...)всех переменных итерации. - Каждая функция сможет наблюдать входные значения
(a...)всех параметров цикла.
Пример. Вследствие шага 1А выше, комбинатор loop имеет следующее свойство:
- Даны
NфразыCn = {null, Sn, Pn}сn = 1..N. - Предполагается, что обработчики предикатов
Pnлибо являютсяnull, либо не имеют параметров. (Только одинPnдолжен быть не-null.) - Предполагается, что обработчики шагов
Snимеют сигнатуры(B1..BX)Rn, для некоторой константыX>=N. - Предполагается, что
Q— это количество типов, отличных от voidRn, а(V1...VQ)— последовательность этих типов. - Должно быть, что
Vn == Bnдляn = 1..min(X,Q). - Типы параметров
Vnбудут интерпретированы как локальные элементы состояния цикла(V...). - Любые оставшиеся типы
BQ+1..BX(еслиQ<X) определят типы параметров конечной обработки цикла(A...).
(A...) были получены из функций шагов, что естественно, если большая часть вычислений цикла происходит в шагах. Для некоторых циклов основная нагрузка вычислений может лежать на функциях pred, и поэтому функции pred могут потребовать принять значения параметров цикла. Для циклов со сложной логикой выхода функции fini могут потребовать принять параметры цикла, и аналогично для циклов со сложной логикой входа, где функции init потребуют дополнительных параметров. По этим причинам правила определения этих параметров являются максимально симметричными для всех частей фраз. В общем случае параметры цикла действуют как общие инвариантные значения во всем цикле, а переменные итерации действуют как общие переменные, меняющиеся со временем, или (если нет функции шага) как внутренние временные инварианты цикла. Выполнение цикла.
- При вызове цикла входные значения цикла сохраняются в локальных переменных, чтобы передаваться каждой функции фразы. Эти локальные переменные инвариантны относительно цикла.
- Каждая функция init выполняется в порядке фраз (передавая внешние аргументы
(a...)) и значения, не являющиесяvoid, сохраняются (как переменные итерации(v...)) в локальные переменные. Эти локальные переменные будут изменяться в цикле (если их шаги не ведут себя как тождественные функции, как указано выше). - Все выполнения функций (кроме функций init) будут получать внутренний список параметров, состоящий из значений переменных итерации, не являющихся
void(в порядке фраз), а затем входных данных цикла(a...)(в порядке аргументов). - Затем функции шага и pred выполняются в порядке фраз (шаг перед pred), пока функция pred не вернет значение
false. - Результат функции шага, не являющейся
void, используется для обновления соответствующего значения в последовательности(v...)переменных цикла. Обновленное значение немедленно видно всем последующим вызовам функций. - Если функция pred возвращает значение
false, вызывается соответствующая функция fini, а возвращаемое значение (типаR) возвращается из цикла в целом. - Если все функции 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с пониманием, что типvoidVбудет незаметно удален из списка параметров, оставляя(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с пониманием, что типvoidVтихо удаляется из списка параметров, оставляя(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с пониманием, что типvoidVтихо удаляется из списка параметров, оставляя(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с пониманием, что типvoidVтихо опускается из списка параметров, оставляя(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, понимая, что типvoidVтихо опускается из списка параметров, оставляя(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