Класс MethodHandles
public final class MethodHandles extends Object
- Методы поиска, помогающие создавать дескрипторы методов для методов и полей.
- Методы-комбинаторы, объединяющие или преобразующие существующие дескрипторы методов в новые.
- Другие фабричные методы для создания дескрипторов методов, имитирующих распространённые операции JVM или шаблоны управления потоком выполнения.
IllegalArgumentException, если тип созданного дескриптора метода будет содержать слишком много параметров.- Начиная с версии:
- 1.7
Краткое описание вложенных классов
| Модификатор и тип | Класс | Описание |
|---|---|---|
static final class |
MethodHandles.Lookup |
Объект поиска — это фабрика для создания дескрипторов методов в случаях, когда при создании требуется проверка доступа. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
static MethodHandle |
arrayConstructor |
Создаёт дескриптор метода, конструирующий массивы заданного типа, как если бы использовался байткод anewarray. |
static MethodHandle |
arrayElementGetter |
Создаёт дескриптор метода, предоставляющий доступ для чтения к элементам массива, как если бы использовался байткод aaload. |
static MethodHandle |
arrayElementSetter |
Создаёт дескриптор метода, предоставляющий доступ для записи к элементам массива, как если бы использовался байткод astore. |
static VarHandle |
arrayElementVarHandle |
Создаёт VarHandle, предоставляющий доступ к элементам массива типа arrayClass. |
static MethodHandle |
arrayLength |
Создаёт дескриптор метода, возвращающий длину массива, как если бы использовался байткод arraylength. |
static VarHandle |
byteArrayViewVarHandle |
Создаёт VarHandle, предоставляющий доступ к элементам массива byte[], рассматриваемого как массив другого примитивного типа, например int[] или long[]. |
static VarHandle |
byteBufferViewVarHandle |
Создаёт VarHandle, предоставляющий доступ к элементам ByteBuffer, рассматриваемого как массив элементов другого примитивного типа, отличного от типа компонента byte, например int[] или long[]. |
static MethodHandle |
catchException |
Создаёт дескриптор метода, адаптирующий целевой дескриптор метода путём его выполнения внутри обработчика исключений. |
static <T> T |
classData |
Возвращает данные класса, связанные с классом поиска заданного объекта поиска caller, или null. |
static <T> T |
classDataAt |
Возвращает элемент с указанным индексом в данных класса, если данные класса, связанные с классом поиска заданного объекта поиска caller, имеют тип List. |
static MethodHandle |
collectArguments |
Адаптирует целевой дескриптор метода, предварительно обрабатывая подпоследовательность его аргументов с помощью фильтра (другого дескриптора метода). |
static VarHandle |
collectCoordinates |
Адаптирует целевой var handle, предварительно обрабатывая подпоследовательность его координатных значений с помощью фильтра (дескриптора метода). |
static MethodHandle |
constant |
Создаёт дескриптор метода с запрошенным типом возвращаемого значения, который при каждом вызове возвращает заданное постоянное значение. |
static MethodHandle |
countedLoop |
Создаёт цикл, выполняющий заданное число итераций. |
static MethodHandle |
countedLoop |
Создаёт цикл, перебирающий диапазон чисел. |
static MethodHandle |
doWhileLoop |
Создаёт цикл do-while из инициализатора, тела и предиката. |
static MethodHandle |
dropArguments |
Создаёт дескриптор метода, который отбрасывает некоторые фиктивные аргументы перед вызовом другого заданного дескриптора метода цели. |
static MethodHandle |
dropArguments |
Создаёт дескриптор метода, который отбрасывает некоторые фиктивные аргументы перед вызовом другого заданного дескриптора метода цели. |
static MethodHandle |
dropArgumentsToMatch |
Адаптирует целевой дескриптор метода к заданному списку типов параметров. |
static VarHandle |
dropCoordinates |
Возвращает var handle, который отбрасывает некоторые фиктивные координаты перед передачей управления целевому var handle. |
static MethodHandle |
dropReturn |
Отбрасывает возвращаемое значение целевого дескриптора (если оно есть). |
static MethodHandle |
empty |
Создаёт дескриптор метода запрошенного типа, который игнорирует любые аргументы, ничего не делает и возвращает подходящее значение по умолчанию в зависимости от типа возвращаемого значения. |
static MethodHandle |
exactInvoker |
Создаёт специальный дескриптор метода-вызовитель, который можно использовать для вызова любого дескриптора метода заданного типа, как если бы применялся invokeExact. |
static MethodHandle |
explicitCastArguments |
Создаёт дескриптор метода, адаптирующий тип заданного дескриптора метода к новому типу путём попарного преобразования типов аргументов и возвращаемого значения. |
static MethodHandle |
filterArguments |
Адаптирует целевой дескриптор метода, предварительно обрабатывая один или несколько его аргументов, каждый с помощью собственной унарной функции-фильтра, а затем вызывая целевой дескриптор с заменой каждого обработанного аргумента результатом соответствующей функции-фильтра. |
static VarHandle |
filterCoordinates |
Адаптирует целевой var handle, предварительно обрабатывая входящие координатные значения с помощью унарных функций-фильтров. |
static MethodHandle |
filterReturnValue |
Адаптирует целевой дескриптор метода, обрабатывая его возвращаемое значение (если оно есть) с помощью фильтра (другого дескриптора метода). |
static VarHandle |
filterValue |
Адаптирует целевой var handle, предварительно обрабатывая входящие и исходящие значения с помощью пары функций-фильтров. |
static MethodHandle |
foldArguments |
Адаптирует целевой дескриптор метода, предварительно обрабатывая некоторые его аргументы, начиная с заданной позиции, а затем вызывая целевой дескриптор, вставляя результат предварительной обработки в исходную последовательность аргументов непосредственно перед аргументами свёртки. |
static MethodHandle |
foldArguments |
Адаптирует целевой дескриптор метода, предварительно обрабатывая некоторые его аргументы, а затем вызывая целевой дескриптор, вставляя результат предварительной обработки в исходную последовательность аргументов. |
static MethodHandle |
guardWithTest |
Создаёт дескриптор метода, адаптирующий целевой дескриптор метода и защищающий его с помощью проверки — дескриптора метода, возвращающего логическое значение. |
static MethodHandle |
identity |
Создаёт дескриптор метода, который при вызове возвращает свой единственный аргумент. |
static MethodHandle |
insertArguments |
Заранее предоставляет целевому дескриптору метода один или несколько связанных аргументов для его вызова. |
static VarHandle |
insertCoordinates |
Заранее предоставляет целевому var handle одну или несколько связанных координат для его вызова. |
static MethodHandle |
invoker |
Создаёт специальный дескриптор метода-вызовитель, который можно использовать для вызова любого дескриптора метода, совместимого с заданным типом, как если бы применялся invoke. |
static MethodHandle |
iteratedLoop |
Создаёт цикл, перебирающий значения, полученные из Iterator<T>. |
static MethodHandles.Lookup |
lookup() |
Возвращает lookup object, обладающий всеми возможностями для имитации поддерживаемых операций байткода вызывающего кода. |
static MethodHandle |
loop |
Создаёт дескриптор метода, представляющий цикл с несколькими переменными цикла, которые обновляются и проверяются на каждой итерации. |
static MethodHandle |
permuteArguments |
Создаёт дескриптор метода, адаптирующий последовательность вызова заданного дескриптора метода к новому типу путём переупорядочивания аргументов. |
static VarHandle |
permuteCoordinates |
Возвращает var handle, адаптирующий координатные значения целевого var handle путём их перестановки так, чтобы новые координаты соответствовали заданным. |
static MethodHandles.Lookup |
privateLookupIn |
Возвращает объект lookup для целевого класса, чтобы имитировать все поддерживаемые операции байткода, включая доступ к закрытым членам. |
static MethodHandles.Lookup |
publicLookup() |
Возвращает lookup object с минимальным уровнем доверия. |
static <T extends Member> |
reflectAs |
Выполняет непроверенное «раскрытие» прямого дескриптора метода. |
static MethodHandle |
spreadInvoker |
Создаёт дескриптор метода, который вызывает любой дескриптор метода типа type, заменяя заданное число завершающих аргументов одним завершающим массивом Object[]. |
static MethodHandle |
tableSwitch |
Создаёт дескриптор метода переключения по таблице, который можно использовать для переключения между набором целевых дескрипторов методов на основе заданного целевого индекса, называемого селектором. |
static MethodHandle |
throwException |
Создаёт дескриптор метода, который выбрасывает исключения заданного типа exType. |
static MethodHandle |
tryFinally |
Создаёт дескриптор метода, адаптирующий дескриптор метода target путём его обёртывания в блок try-finally. |
static MethodHandle |
varHandleExactInvoker |
Создаёт специальный дескриптор метода-вызовитель, который можно использовать для вызова метода режима доступа с полиморфной сигнатурой у любого VarHandle, связанный с которым тип режима доступа совместим с заданным типом. |
static MethodHandle |
varHandleInvoker |
Создаёт специальный дескриптор метода-вызовитель, который можно использовать для вызова метода режима доступа с полиморфной сигнатурой у любого VarHandle, связанный с которым тип режима доступа совместим с заданным типом. |
static MethodHandle |
whileLoop |
Создаёт цикл while из инициализатора, тела и предиката. |
static MethodHandle |
zero |
Создаёт константный дескриптор метода с запрошенным типом возвращаемого значения, который при каждом вызове возвращает значение по умолчанию для этого типа. |
Подробное описание методов
lookup
public static MethodHandles.Lookup lookup()
lookup object с полными возможностями для эмуляции всех поддерживаемых вариантов поведения байт-кода вызывающего кода. Эти возможности включают полный привилегированный доступ к вызывающему коду. Фабричные методы объекта поиска могут создавать прямые дескрипторы методов для любых элементов, к которым вызывающий код имеет доступ через байт-код, включая защищённые и закрытые поля и методы. Этот объект поиска создаётся исходным классом поиска и имеет установленный бит ORIGINAL. Этот объект поиска является полномочием, которое можно делегировать доверенным агентам. Не храните его там, где к нему может получить доступ недоверенный код. Этот метод чувствителен к вызывающему коду, то есть может возвращать разные значения разным вызывающим сторонам. Если MethodHandles.lookup вызывается из контекста, в котором в стеке нет кадра вызывающего кода (например, при непосредственном вызове из присоединённого потока JNI), выбрасывается IllegalCallerException. Чтобы получить lookup object в таком контексте, используйте вспомогательный класс, который будет неявно определён как вызывающий код, или используйте publicLookup(), чтобы получить поиск с ограниченными привилегиями.
- Возвращает:
- объект поиска для вызывающего этот метод кода, с исходным и полным привилегированным доступом.
- Выбрасывает:
-
IllegalCallerException— если в стеке нет кадра вызывающего кода.
publicLookup
public static MethodHandles.Lookup publicLookup()
lookup object с минимальным уровнем доверия. Поиск имеет режим UNCONDITIONAL. Его можно использовать только для создания дескрипторов методов для открытых элементов открытых классов в пакетах, экспортируемых безусловно. Согласно общепринятому соглашению, класс поиска этого объекта поиска будет Object.
- Примечание API:
- Использование Object основано на соглашении, а поскольку режимы поиска ограничены, специальный доступ к внутренним компонентам Object, его пакету или модулю не предоставляется. Этот общедоступный объект поиска или другой объект поиска с режимом
UNCONDITIONALпредполагает доступность для чтения. Следовательно, класс поиска не используется для определения контекста поиска.Обсуждение: Класс поиска можно изменить на любой другой класс
Cс помощью выражения видаpublicLookup().in(C.class). Кроме того, он не может получать доступ к методам, чувствительным к вызывающему коду. - Возвращает:
- объект поиска с минимальным уровнем доверия
privateLookupIn
public static MethodHandles.Lookup privateLookupIn(Class<?> targetClass, MethodHandles.Lookup caller) throws IllegalAccessException
lookup для целевого класса, способный эмулировать все поддерживаемые варианты поведения байт-кода, включая закрытый доступ. Возвращённый объект поиска может предоставлять доступ к классам в модулях и пакетах, а также к элементам этих классов, за пределами обычных правил управления доступом в Java, следуя вместо этого более разрешительным правилам модульной глубокой рефлексии. Вызывающему коду, представленному объектом Lookup, в модуле M1 разрешена глубокая рефлексия в модуле M2 и пакете целевого класса тогда и только тогда, когда выполняются все следующие условия true:
- Объект поиска вызывающего кода должен иметь полный привилегированный доступ. В частности:
- Объект поиска вызывающего кода должен иметь режим поиска
MODULE. (Это необходимо, поскольку в противном случае нельзя было бы гарантировать, что исходный создатель объекта поиска является членом какого-либо конкретного модуля, и поэтому любые последующие проверки читаемости и квалифицированного экспорта оказались бы неэффективными.) - Объект поиска вызывающего кода должен иметь доступ
PRIVATE. (Это необходимо, поскольку приложение, намеревающееся совместно использовать доступ внутри модуля только с помощьюMODULE, непреднамеренно предоставит также доступ к глубокой рефлексии в собственном модуле.)
- Объект поиска вызывающего кода должен иметь режим поиска
- Целевой класс должен быть обычным классом, а не примитивным классом или массивом. (Таким образом,
M2определено.) - Если модуль вызывающего кода
M1отличается от целевого модуляM2, должны выполняться оба следующих условия:
Если любое из указанных выше условий не выполняется, этот метод завершается исключением.
В противном случае, если M1 и M2 являются одним и тем же модулем, этот метод возвращает Lookup для targetClass с полным привилегированным доступом и null в качестве предыдущего класса поиска.
В противном случае M1 и M2 являются разными модулями. Этот метод возвращает Lookup для targetClass, в котором класс поиска вызывающего кода записан как новый предыдущий класс поиска, с доступом PRIVATE, но без доступа MODULE.
Полученный объект Lookup не имеет доступа ORIGINAL.
- Примечание API:
- Объект
Lookup, возвращаемый этим методом, может определять классы в пакете времени выполнения классаtargetClass. При открытии пакета другому модулю следует проявлять крайнюю осторожность, поскольку такие определённые классы имеют такой же полный привилегированный доступ, как и другие элементы модуляtargetClass. - Параметры:
-
targetClass— целевой класс -
caller— объект поиска вызывающего кода - Возвращает:
- объект поиска для целевого класса с закрытым доступом
- Выбрасывает:
-
IllegalArgumentException— еслиtargetClassявляется примитивным типом, типом void или массивом -
NullPointerException— еслиtargetClassилиcallerравноnull -
IllegalAccessException— если любая из других описанных выше проверок доступа завершается неудачей - Начиная с версии:
- 9
- См. также:
classData
public static <T> T classData(MethodHandles.Lookup caller, String name, Class<T> type) throws IllegalAccessException
caller, или null. Скрытый класс с данными класса можно создать вызовом Lookup::defineHiddenClassWithClassData. Если статический инициализатор класса поиска заданного объекта поиска caller ещё не был выполнен, этот метод приведёт к его выполнению.
Скрытые классы, созданные с помощью Lookup::defineHiddenClass, и нескрытые классы не имеют данных класса. Если вызвать этот метод для объекта поиска этих классов, будет возвращено null.
Для получения данных класса режимы поиска этого объекта поиска должны включать исходный доступ.
- Примечание API:
- Этот метод можно вызывать как bootstrap-метод для динамически вычисляемой константы. Например, платформа может создать скрытый класс с данными класса, которые могут быть
Classили объектомMethodHandle. Данные класса доступны только объекту поиска, созданному исходным вызывающим кодом, но недоступны другим элементам того же гнезда. Если платформа передаёт скрытому классу объекты, связанные с безопасностью, через данные класса, рекомендуется загружать значение данных класса как динамически вычисляемую константу, а не хранить данные класса в закрытых статических полях, доступных другим участникам гнезда. - Параметры типа:
T— тип, к которому следует привести объект данных класса- Параметры:
-
caller— контекст поиска, описывающий класс, выполняющий операцию (обычно помещается в стек JVM) -
name— должно бытьConstantDescs.DEFAULT_NAME("_") -
type— тип данных класса - Возвращает:
- значение данных класса, если они присутствуют в классе поиска; в противном случае —
null - Выбрасывает:
-
IllegalArgumentException— если имя не равно"_" -
IllegalAccessException— если контекст поиска не имеет исходного доступа -
ClassCastException— если данные класса нельзя преобразовать к заданному типуtype -
NullPointerException— если аргументcallerилиtypeравенnull - См. Спецификацию виртуальной машины Java:
- 5.5 Инициализация
- Начиная с версии:
- 16
- См. также:
classDataAt
public static <T> T classDataAt(MethodHandles.Lookup caller, String name, Class<T> type, int index) throws IllegalAccessException
caller, имеют тип List. Если в этом классе поиска данные класса отсутствуют, метод возвращает null. Скрытый класс с данными класса можно создать вызовом Lookup::defineHiddenClassWithClassData. Если статический инициализатор класса поиска заданного объекта поиска caller ещё не был выполнен, этот метод приведёт к его выполнению.
Скрытые классы, созданные с помощью Lookup::defineHiddenClass, и нескрытые классы не имеют данных класса. Если вызвать этот метод для объекта поиска этих классов, будет возвращено null.
Для получения данных класса режимы поиска этого объекта поиска должны включать исходный доступ.
- Примечание API:
- Этот метод можно вызывать как bootstrap-метод для динамически вычисляемой константы. Например, платформа может создать скрытый класс с данными класса, такими как
List.of(o1, o2, o3....), содержащими несколько объектов, и использовать этот метод для загрузки элемента по заданному индексу. Данные класса доступны только объекту поиска, созданному исходным вызывающим кодом, но недоступны другим элементам того же гнезда. Если платформа передаёт скрытому классу объекты, связанные с безопасностью, через данные класса, рекомендуется загружать значение данных класса как динамически вычисляемую константу, а не хранить данные класса в закрытых статических полях, доступных другим участникам гнезда. - Параметры типа:
T— тип, к которому следует привести возвращаемый объект- Параметры:
-
caller— контекст поиска, описывающий класс, выполняющий операцию (обычно помещается в стек JVM) -
name— должно бытьConstantDescs.DEFAULT_NAME("_") -
type— тип элемента по указанному индексу в данных класса -
index— индекс элемента в данных класса - Возвращает:
- элемент по заданному индексу в данных класса, если данные класса присутствуют; в противном случае —
null - Выбрасывает:
-
IllegalArgumentException— если имя не равно"_" -
IllegalAccessException— если контекст поиска не имеет исходного доступа -
ClassCastException— если данные класса нельзя преобразовать кListили элемент по указанному индексу нельзя преобразовать к заданному типу -
IndexOutOfBoundsException— если индекс выходит за допустимый диапазон -
NullPointerException— если аргументcallerилиtypeравенnull; либо если операция распаковки завершается неудачей, поскольку элемент по заданному индексу имеет значениеnull - Начиная с версии:
- 16
- См. также:
reflectAs
public static <T extends Member> T reflectAs(Class<T> expected, MethodHandle target)
Lookup.revealDirect, чтобы получить его символьную ссылку, а затем вызвал MethodHandleInfo.reflectAs, чтобы разрешить символьную ссылку в элемент.- Параметры типа:
T— требуемый тип результата:Memberили его подтип- Параметры:
-
expected— объект класса, представляющий требуемый тип результатаT -
target— прямой дескриптор метода, который требуется раскрыть на компоненты символьной ссылки - Возвращает:
- ссылку на объект метода, конструктора или поля
- Выбрасывает:
-
NullPointerException— если любой из аргументов равенnull -
IllegalArgumentException— если цель не является прямым дескриптором метода -
ClassCastException— если элемент не имеет ожидаемого типа - Начиная с версии:
- 1.8
arrayConstructor
public static MethodHandle arrayConstructor(Class<?> arrayClass) throws IllegalArgumentException
anewarray. Типом возвращаемого значения дескриптора метода будет тип массива. Типом его единственного аргумента будет int, задающий размер массива. Если вызвать возвращённый дескриптор метода с отрицательным размером массива, будет выброшено исключение NegativeArraySizeException.
- Параметры:
-
arrayClass— тип массива - Возвращает:
- дескриптор метода, создающий массивы заданного типа
- Выбрасывает:
-
NullPointerException— если аргумент равенnull -
IllegalArgumentException— еслиarrayClassне является типом массива - См. Спецификацию виртуальной машины Java:
- 6.5 Инструкция
anewarray
- Начиная с версии:
- 9
- См. также:
arrayLength
public static MethodHandle arrayLength(Class<?> arrayClass) throws IllegalArgumentException
arraylength. Тип возвращаемого значения дескриптора метода — int, а его единственный аргумент имеет тип массива. Если вызвать возвращённый дескриптор метода с ссылкой на массив null, будет выброшено исключение NullPointerException.
- Параметры:
-
arrayClass— тип массива - Возвращает:
- дескриптор метода, позволяющий получить длину массива заданного типа
- Выбрасывает:
-
NullPointerException— если аргумент равенnull -
IllegalArgumentException— если arrayClass не является типом массива - См. Спецификацию виртуальной машины Java:
- 6.5 Инструкция
arraylength
- Начиная с версии:
- 9
arrayElementGetter
public static MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException
aaload. Тип возвращаемого значения дескриптора метода совпадает с типом элементов массива. Его первым аргументом будет тип массива, а вторым — int. При вызове возвращённого дескриптора метода проверяются ссылка на массив и индекс массива. Если ссылка на массив равна null, будет выброшено исключение NullPointerException; если индекс отрицательный или больше либо равен длине массива, будет выброшено исключение ArrayIndexOutOfBoundsException.
- Параметры:
-
arrayClass— тип массива - Возвращает:
- дескриптор метода, позволяющий загружать значения из массива заданного типа
- Выбрасывает:
-
NullPointerException— если аргумент равен null -
IllegalArgumentException— если arrayClass не является типом массива - См. Спецификацию виртуальной машины Java:
- 6.5 Инструкция
aaload
arrayElementSetter
public static MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException
astore. Тип возвращаемого значения дескриптора метода — void. Его последним аргументом будет тип элементов массива. Первый и второй аргументы — тип массива и int. При вызове возвращённого дескриптора метода проверяются ссылка на массив и индекс массива. Если ссылка на массив равна null, будет выброшено исключение NullPointerException; если индекс отрицательный или больше либо равен длине массива, будет выброшено исключение ArrayIndexOutOfBoundsException.
- Параметры:
-
arrayClass— класс массива - Возвращает:
- дескриптор метода, позволяющий сохранять значения в массив заданного типа
- Выбрасывает:
-
NullPointerException— если аргумент равен null -
IllegalArgumentException— если arrayClass не является типом массива - См. Спецификацию виртуальной машины Java:
- 6.5 Инструкция
aastore
arrayElementVarHandle
public static VarHandle arrayElementVarHandle(Class<?> arrayClass) throws IllegalArgumentException
arrayClass. Тип переменной VarHandle — тип компонента arrayClass, а список типов координат — (arrayClass, int), где тип координаты int соответствует аргументу, задающему индекс в массиве. При следующих условиях некоторые режимы доступа возвращённого VarHandle не поддерживаются:
- если тип компонента не является
byte,short,char,int,long,floatилиdouble, то режимы атомарного обновления числовых значений не поддерживаются. - если тип компонента не является
boolean,byte,short,char,intилиlong, то режимы побитового атомарного обновления не поддерживаются.
Если тип компонента — float или double, то режимы числового и атомарного обновления сравнивают значения по их побитовому представлению (см. соответственно Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double)).
При вызове возвращённого VarHandle проверяются ссылка на массив и индекс массива. Если ссылка на массив равна null, будет выброшено исключение NullPointerException; если индекс отрицательный или больше либо равен длине массива, будет выброшено исключение ArrayIndexOutOfBoundsException.
- Примечание API:
- Побитовое сравнение значений
floatилиdouble, выполняемое режимами числового и атомарного обновления, отличается от примитивного оператора==и методовFloat.equals(Object)иDouble.equals(Object), в частности, при сравнении значений NaN или сравнении-0.0с+0.0. При выполнении операций compare-and-set или compare-and-exchange с такими значениями следует соблюдать осторожность, поскольку операция может неожиданно завершиться неудачей. В Java существует множество значений NaN, которые считаютсяNaN, хотя ни одна операция с плавающей запятой IEEE 754, предоставляемая Java, не может различить их. Операция может завершиться неудачей, если ожидаемое значение или значение-свидетель является NaN и преобразуется (возможно, специфичным для платформы способом) в другое значение NaN, имеющее иное побитовое представление (подробнее см.Float.intBitsToFloat(int)илиDouble.longBitsToDouble(long)). Значения-0.0и+0.0имеют разные побитовые представления, но считаются равными при использовании примитивного оператора==. Например, операция может завершиться неудачей, если числовой алгоритм вычислит ожидаемое значение, скажем,-0.0, а ранее вычисленное значение-свидетель окажется, скажем,+0.0. - Параметры:
-
arrayClass— класс массива типаT[] - Возвращает:
- VarHandle, предоставляющий доступ к элементам массива
- Выбрасывает:
-
NullPointerException— если arrayClass равен null -
IllegalArgumentException— если arrayClass не является типом массива - Начиная с версии:
- 9
byteArrayViewVarHandle
public static VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder) throws IllegalArgumentException
byte[], интерпретируемого как массив другого примитивного типа, например int[] или long[]. Тип переменной VarHandle — тип компонента viewArrayClass, а список типов координат — (byte[], int), где тип координаты int соответствует аргументу, задающему индекс в массиве byte[]. Возвращённый VarHandle обращается к байтам по индексу в массиве byte[] и объединяет байты в значение типа компонента viewArrayClass или разбивает его на байты согласно заданному порядку байтов. Поддерживаемые типы компонентов (типы переменных): short, char, int, long, float и double.
Доступ к байтам по заданному индексу приведёт к ArrayIndexOutOfBoundsException, если индекс меньше 0 или больше длины массива byte[] за вычетом размера (в байтах) T.
Возвращённый VarHandle поддерживает только обычные режимы доступа get и set. Для всех остальных режимов доступа будет выброшено исключение UnsupportedOperationException.
- Примечание API:
- Если требуются режимы доступа, отличные от обычного доступа, клиентам следует рассмотреть возможность использования памяти вне кучи через прямые буферы байтов или сегменты памяти вне кучи, либо сегменты памяти, основанные на
long[], для которых можно обеспечить более строгие гарантии выравнивания. - Параметры:
-
viewArrayClass— класс массива-представления с типом компонентаT -
byteOrder— порядок байтов элементов массива-представления, хранящихся в базовом массивеbyte - Возвращает:
- VarHandle, предоставляющий доступ к элементам массива
byte[], интерпретируемого как элементы, соответствующие типу компонентов класса массива-представления - Выбрасывает:
-
NullPointerException— если viewArrayClass или byteOrder равен null -
IllegalArgumentException— если viewArrayClass не является типом массива -
UnsupportedOperationException— если тип компонента viewArrayClass не поддерживается в качестве типа переменной - Начиная с версии:
- 9
byteBufferViewVarHandle
public static VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder) throws IllegalArgumentException
ByteBuffer, рассматриваемого как массив элементов другого примитивного типа компонента, отличного от типа byte, например int[] или long[]. Тип переменной VarHandle — тип компонента viewArrayClass, а список типов координат — (ByteBuffer, int), где тип координаты int соответствует аргументу, который является индексом в массиве byte[]. Возвращаемый VarHandle обращается к байтам по индексу в ByteBuffer, объединяя байты в значение типа компонента viewArrayClass или разбивая его на байты в соответствии с заданным порядком байтов. Поддерживаются следующие типы компонентов (типы переменных): short, char, int, long, float и double.
Если ByteBuffer доступен только для чтения, любая операция доступа, кроме режимов чтения, приведёт к ReadOnlyBufferException.
Доступ к байтам по заданному индексу приведёт к IndexOutOfBoundsException, если индекс меньше 0 или больше предельного значения ByteBuffer за вычетом размера (в байтах) T.
Для байтовых буферов в куче доступ всегда является невыровненным. В результате возвращаемый дескриптор переменной поддерживает только обычные режимы доступа get и set. Для всех остальных режимов доступа будет выброшено исключение IllegalStateException.
Только для прямых буферов доступ к байтам по индексу может быть выровненным или невыровненным для T относительно базового адреса памяти, то есть A, связанного с ByteBuffer и индексом. Если доступ невыровнен, то доступ в любом режиме, кроме режимов get и set, приведёт к IllegalStateException. В таких случаях атомарный доступ гарантируется только относительно наибольшей степени двойки, на которую делится НОД A и размера (в байтах) T. Если доступ выровнен, поддерживаются следующие режимы доступа, для которых гарантируется атомарный доступ:
- режимы доступа для чтения и записи для всех
T. Режимы доступаgetиsetдляlongиdoubleподдерживаются, но не гарантируют атомарность, как описано в разделе 17.7 Спецификации языка Java. - режимы атомарного обновления для
int,long,floatилиdouble. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные типы.) - режимы числового атомарного обновления для
intиlong. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные числовые типы.) - режимы побитового атомарного обновления для
intиlong. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные числовые типы.)
Невыровненный доступ и, следовательно, гарантии атомарности для ByteBuffer, bb (прямого или иного), index, T и соответствующего ему упакованного типа, T_BOX можно определить следующим образом:
int sizeOfT = T_BOX.BYTES; // size in bytes of T
ByteBuffer bb = ...
int misalignedAtIndex = bb.alignmentOffset(index, sizeOfT);
boolean isMisaligned = misalignedAtIndex != 0;
Если тип переменной — float или double, то режимы атомарного обновления сравнивают значения по их битовому представлению (см. соответственно Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double)).
- Параметры:
-
viewArrayClass— класс массива-представления с типом компонентаT -
byteOrder— порядок байтов элементов массива-представления, сохранённых в базовомByteBuffer(обратите внимание: он имеет приоритет над порядком байтов вByteBuffer) - Возвращает:
- VarHandle, предоставляющий доступ к элементам
ByteBuffer, рассматриваемого как элементы, соответствующие типу компонента класса массива-представления - Вызывает:
-
NullPointerException— если viewArrayClass или byteOrder равен null -
IllegalArgumentException— если viewArrayClass не является типом массива -
UnsupportedOperationException— если тип компонента viewArrayClass не поддерживается как тип переменной - С версии:
- 9
spreadInvoker
public static MethodHandle spreadInvoker(MethodType type, int leadingArgCount)
type, заменяя заданное количество конечных аргументов одним конечным массивом Object[]. Полученный дескриптор вызова будет иметь следующие аргументы: - одна целевая
MethodHandle - ноль или более начальных значений (количество задаётся параметром
leadingArgCount) - массив
Object[], содержащий конечные аргументы
Дескриптор вызова вызывает свою цель так же, как вызов invoke с указанным type. То есть, если тип цели точно совпадает с заданным type, поведение будет таким же, как у invokeExact; в противном случае поведение будет таким, как если бы для преобразования цели к требуемому type использовался asType.
Тип возвращаемого дескриптора вызова не будет совпадать с заданным type: все параметры, кроме первых leadingArgCount, будут заменены одним массивом типа Object[], который станет последним параметром.
Перед вызовом цели дескриптор вызова развернёт конечный массив, при необходимости выполнит приведение ссылочных типов, а также распаковку и расширение примитивных аргументов. Если при вызове дескриптора переданный аргумент-массив содержит неверное количество элементов, дескриптор вызовет IllegalArgumentException вместо вызова цели.
Этот метод эквивалентен следующему коду (хотя может быть более эффективным):
MethodHandle invoker = MethodHandles.invoker(type);
int spreadArgCount = type.parameterCount() - leadingArgCount;
invoker = invoker.asSpreader(Object[].class, spreadArgCount);
return invoker;
- Параметры:
-
type— требуемый тип цели -
leadingArgCount— количество фиксированных аргументов, передаваемых цели без изменений - Возвращает:
- дескриптор метода, подходящий для вызова любого дескриптора метода заданного типа
- Вызывает:
-
NullPointerException— еслиtypeравен null -
IllegalArgumentException— еслиleadingArgCountне входит в диапазон от 0 доtype.parameterCount()включительно или если тип полученного дескриптора метода будет содержать слишком много параметров
exactInvoker
public static MethodHandle exactInvoker(MethodType type)
invokeExact. Тип полученного дескриптора вызова будет в точности совпадать с требуемым типом, за исключением дополнительного начального аргумента типа MethodHandle. Этот метод эквивалентен следующему коду (хотя может быть более эффективным): publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
Обсуждение: Дескрипторы методов-вызовов могут быть полезны при работе с дескрипторами методов переменной, типы которых неизвестны. Например, чтобы эмулировать вызов invokeExact дескриптора метода переменной M, извлеките его тип T, найдите дескриптор метода-вызова X для T и вызовите этот дескриптор метода, как X.invoke(T, A...). Вызвать X.invokeExact не получится, поскольку тип T неизвестен. Если требуется развернуть, собрать или иным образом преобразовать аргументы, эти преобразования можно один раз применить к дескриптору вызова X и повторно использовать для множества значений дескриптора метода M, если они совместимы с типом X.
(Примечание: дескриптор метода-вызова недоступен через API базовой рефлексии. Попытка вызвать java.lang.reflect.Method.invoke для объявленного метода invokeExact или invoke приведёт к исключению UnsupportedOperationException.)
Этот метод не вызывает рефлексивных исключений.
- Параметры:
-
type— требуемый тип цели - Возвращает:
- дескриптор метода, подходящий для вызова любого дескриптора метода заданного типа
- Вызывает:
-
IllegalArgumentException— если тип полученного дескриптора метода будет содержать слишком много параметров
invoker
public static MethodHandle invoker(MethodType type)
invoke. Тип полученного дескриптора вызова будет в точности совпадать с требуемым типом, за исключением дополнительного начального аргумента типа MethodHandle. Перед вызовом цели, если её тип отличается от ожидаемого, дескриптор вызова при необходимости выполнит приведение ссылочных типов, упаковку, распаковку или расширение примитивных значений, как если бы использовался asType. Аналогичным образом при необходимости будет преобразовано возвращаемое значение. Если цель — дескриптор метода с переменной арностью, будет выполнено необходимое преобразование арности, опять же так, как если бы использовался asType.
Этот метод эквивалентен следующему коду (хотя может быть более эффективным): publicLookup().findVirtual(MethodHandle.class, "invoke", type)
Обсуждение: обобщённый тип метода содержит только аргументы и возвращаемые значения типа Object. Дескриптор вызова для такого типа способен вызывать любой дескриптор метода с той же арностью, что и у обобщённого типа.
(Примечание: дескриптор метода-вызова недоступен через API базовой рефлексии. Попытка вызвать java.lang.reflect.Method.invoke для объявленного метода invokeExact или invoke приведёт к исключению UnsupportedOperationException.)
Этот метод не вызывает рефлексивных исключений.
- Параметры:
-
type— требуемый тип цели - Возвращает:
- дескриптор метода, подходящий для вызова любого дескриптора метода, преобразуемого к заданному типу
- Вызывает:
-
IllegalArgumentException— если тип полученного дескриптора метода будет содержать слишком много параметров
varHandleExactInvoker
public static MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode, MethodType type)
VarHandle.- Параметры:
-
accessMode— режим доступа VarHandle -
type— требуемый тип цели - Возвращает:
- дескриптор метода, подходящий для вызова метода режима доступа любого VarHandle, тип режима доступа которого совпадает с заданным типом.
- С версии:
- 9
varHandleInvoker
public static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type)
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— если преобразование невозможно выполнить - См. также:
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
- См. также:
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
- См. также:
insertArguments
public static MethodHandle insertArguments(MethodHandle target, int pos, Object... values)
Тип нового дескриптора метода не будет содержать типы связанных параметров исходного типа цели, поскольку вызывающим сторонам нового дескриптора метода больше не нужно передавать эти аргументы.
Каждый заданный объект-аргумент должен соответствовать типу связанного параметра. Если тип связанного параметра примитивный, объект-аргумент должен быть объектом-обёрткой; для получения примитивного значения он будет распакован.
Аргумент pos задаёт параметры для связывания. Его значение может находиться в диапазоне от нуля до N-L включительно, где N — арность целевого дескриптора метода, а L — длина массива значений.
Примечание: полученный адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода был таким.
- Параметры:
-
target— дескриптор метода, который нужно вызвать после вставки аргумента -
pos— место вставки аргумента (ноль означает первый аргумент) -
values— последовательность вставляемых аргументов - Возвращает:
- дескриптор метода, который вставляет дополнительный аргумент перед вызовом исходного дескриптора метода
- Вызывает:
-
NullPointerException— если цель или массивvaluesравны null -
IllegalArgumentException— еслиposменьше0или большеN - L, гдеN— арность целевого дескриптора метода, аL— длина массива значений. -
ClassCastException— если аргумент не соответствует типу связанного параметра. - См. также:
dropArguments
public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)
Аргумент pos может принимать значения от нуля до N, где N — арность цели. Если pos равен нулю, фиктивные аргументы предшествуют настоящим аргументам цели; если pos равен N, они следуют за ними.
Пример:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
assertEquals(bigType, d0.type());
assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
Этот метод также эквивалентен следующему коду:
dropArguments(target, pos, valueTypes.toArray(new Class[0]))
- Параметры:
-
target— дескриптор метода, который нужно вызвать после отбрасывания аргументов -
pos— позиция первого отбрасываемого аргумента (ноль означает самый левый) -
valueTypes— тип или типы отбрасываемых аргументов - Возвращает:
- дескриптор метода, который отбрасывает аргументы заданных типов перед вызовом исходного дескриптора метода
- Вызывает:
-
NullPointerException— если цель равна null, либо списокvalueTypesили любой его элемент равен null -
IllegalArgumentException— если любой элементvalueTypesявляетсяvoid.class, еслиposотрицателен или превышает арность цели либо если тип нового дескриптора метода будет содержать слишком много параметров
dropArguments
public static MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
Аргумент pos может принимать значения от нуля до N, где N — арность целевого дескриптора. Если pos равно нулю, фиктивные аргументы будут предшествовать реальным аргументам целевого дескриптора; если pos равно N, они будут следовать за ними.
- Примечание API:
-
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); assertEquals("xy", (String) cat.invokeExact("x", "y")); MethodHandle d0 = dropArguments(cat, 0, String.class); assertEquals("yz", (String) d0.invokeExact("x", "y", "z")); MethodHandle d1 = dropArguments(cat, 1, String.class); assertEquals("xz", (String) d1.invokeExact("x", "y", "z")); MethodHandle d2 = dropArguments(cat, 2, String.class); assertEquals("xy", (String) d2.invokeExact("x", "y", "z")); MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class); assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));Этот метод также эквивалентен следующему коду:
dropArguments(target, pos, Arrays.asList(valueTypes)) - Параметры:
-
target— дескриптор метода, вызываемый после отбрасывания аргументов -
pos— позиция первого отбрасываемого аргумента (ноль для крайнего левого) -
valueTypes— тип или типы отбрасываемых аргументов - Возвращает:
- дескриптор метода, который отбрасывает аргументы заданных типов перед вызовом исходного дескриптора метода
- Вызывает:
-
NullPointerException— если целевой дескриптор равен null либо массивvalueTypesили любой из его элементов равен null -
IllegalArgumentException— если любой элементvalueTypesравенvoid.class, еслиposотрицательно или больше арности целевого дескриптора либо если тип нового дескриптора метода будет иметь слишком много параметров
dropArgumentsToMatch
public static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos)
target должны быть подсписком списка типов newTypes, начиная с позиции pos. Полученный дескриптор будет содержать список типов параметров целевого дескриптора, а все несовпадающие типы параметров (до или после совпадающего подсписка) будут вставлены в соответствующие позиции исходных параметров целевого дескриптора, как если бы был вызван dropArguments(MethodHandle, int, Class[]). Полученный дескриптор будет иметь тот же тип возвращаемого значения, что и целевой дескриптор.
В более формальном изложении предположим, что имеются следующие два списка типов:
- Целевой дескриптор содержит список типов параметров
S..., M..., в котором число типовSзадано значениемskip. ТипыM— это типы, которые должны совпасть с частью заданного списка типовnewTypes. - Список
newTypesсодержит типыP..., M..., A..., в котором число типовPзадано значениемpos. ТипыM— это именно те типы, с которыми должны совпасть типыMв списке типов параметров целевого дескриптора. Типы вA— это дополнительные типы после совпадающего подсписка.
dropArgumentsToMatch будет иметь список типов параметров S..., P..., M..., A..., причем типы P и A будут вставлены так, как если бы был вызван dropArguments(MethodHandle, int, Class[]).- Примечание API:
- Два дескриптора метода, списки аргументов которых «эффективно идентичны» (то есть имеют общий идентичный префикс), можно взаимно преобразовать к общему типу двумя вызовами
dropArgumentsToMatchследующим образом:import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... ... MethodHandle h0 = constant(boolean.class, true); MethodHandle h1 = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodType bigType = h1.type().insertParameterTypes(1, String.class, int.class); MethodHandle h2 = dropArguments(h1, 0, bigType.parameterList()); if (h1.type().parameterCount() < h2.type().parameterCount()) h1 = dropArgumentsToMatch(h1, 0, h2.type().parameterList(), 0); // lengthen h1 else h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0); // lengthen h2 MethodHandle h3 = guardWithTest(h0, h1, h2); assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c")); - Параметры:
-
target— адаптируемый дескриптор метода -
skip— число игнорируемых параметров целевого дескриптора (они останутся без изменений) -
newTypes— список типов, которому должен соответствовать список типов параметровtarget -
pos— позиция вnewTypes, где должны находиться параметры целевого дескриптора, не подлежащие пропуску - Возвращает:
- возможно, адаптированный дескриптор метода
- Вызывает:
-
NullPointerException— если любой из аргументов равен null -
IllegalArgumentException— если любой элементnewTypesравенvoid.class, еслиskipотрицательно или больше арности целевого дескриптора, еслиposотрицательно или больше размера списка newTypes либо еслиnewTypesне содержит пропускаемые параметрыtargetв позицииpos. - Начиная с версии:
- 9
dropReturn
public static MethodHandle dropReturn(MethodHandle target)
void.- Параметры:
-
target— адаптируемый дескриптор метода - Возвращает:
- возможно, адаптированный дескриптор метода
- Вызывает:
-
NullPointerException— еслиtargetравен null - Начиная с версии:
- 16
filterArguments
public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters)
Предварительная обработка выполняется одним или несколькими дескрипторами методов, указанными в элементах массива filters. Первый элемент массива фильтров соответствует аргументу pos целевого дескриптора, следующий — следующему аргументу и так далее. Функции-фильтры вызываются слева направо.
Аргументы null в массиве рассматриваются как тождественные функции, а соответствующие аргументы остаются без изменений. (Если в массиве нет ненулевых элементов, возвращается исходный целевой дескриптор.) Каждый фильтр применяется к соответствующему аргументу адаптера.
Если фильтр F применяется к аргументу целевого дескриптора с номером N, то F должен быть дескриптором метода, принимающим ровно один аргумент. Тип единственного аргумента F заменяет соответствующий тип аргумента целевого дескриптора в результирующем адаптированном дескрипторе метода. Тип возвращаемого значения F должен совпадать с типом соответствующего параметра целевого дескриптора.
Наличие элементов filters (null или иных), не соответствующих позициям аргументов целевого дескриптора, является ошибкой.
Пример:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle upcase = lookup().findVirtual(String.class,
"toUpperCase", methodType(String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle f0 = filterArguments(cat, 0, upcase);
assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
MethodHandle f1 = filterArguments(cat, 1, upcase);
assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
Ниже приведен псевдокод результирующего адаптера. В коде T обозначает тип возвращаемого значения как target, так и результирующего адаптера. P/p и B/b обозначают типы и значения параметров и аргументов, предшествующих позиции фильтра pos и следующих за ней соответственно. A[i]/a[i] обозначают типы и значения фильтруемых параметров и аргументов; они также представляют типы возвращаемых значений дескрипторов filter[i]. Последние принимают аргументы v[i] типа V[i], которые также присутствуют в сигнатуре результирующего адаптера.
T target(P... p, A[i]... a[i], B... b);
A[i] filter[i](V[i]);
T adapter(P... p, V[i]... v[i], B... b) {
return target(p..., filter[i](v[i])..., b...);
}
Примечание: Результирующий адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода им был.
- Параметры:
-
target— дескриптор метода, вызываемый после фильтрации аргументов -
pos— позиция первого фильтруемого аргумента -
filters— дескрипторы методов, первоначально вызываемые для фильтруемых аргументов - Возвращает:
- дескриптор метода, включающий указанную логику фильтрации аргументов
- Вызывает:
-
NullPointerException— если целевой дескриптор равен null или массивfiltersравен null -
IllegalArgumentException— если ненулевой элементfiltersне соответствует типу соответствующего аргумента целевого дескриптора, как описано выше, еслиpos+filters.lengthбольшеtarget.type().parameterCount()либо если тип результирующего дескриптора метода будет иметь слишком много параметров
collectArguments
public static MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter)
Если фильтр возвращает значение, целевой дескриптор должен принимать это значение в качестве аргумента в позиции pos, перед которым и/или после которого могут находиться аргументы, не передаваемые фильтру. Если фильтр возвращает void, целевой дескриптор должен принимать все аргументы, не передаваемые фильтру. Аргументы не меняют порядок, а результат, возвращенный фильтром, заменяет (по порядку) всю подпоследовательность аргументов, изначально переданных адаптеру.
Типы аргументов фильтра (если они есть) заменяют в результирующем адаптированном дескрипторе метода ноль или один тип аргумента целевого дескриптора в позиции pos. Тип возвращаемого значения фильтра (если он есть) должен совпадать с типом аргумента целевого дескриптора в позиции pos, а этот аргумент целевого дескриптора получает значение, возвращенное фильтром.
Во всех случаях pos должно быть больше или равно нулю, а pos также должно быть меньше или равно арности целевого дескриптора.
Пример:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle deepToString = publicLookup()
.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
assertEquals("[strange]", (String) ts1.invokeExact("strange"));
MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
assertEquals("[top, [up, down], strange]",
(String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
assertEquals("[top, [up, down], [strange]]",
(String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
assertEquals("[top, [[up, down, strange], charm], bottom]",
(String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
Ниже приведен псевдокод результирующего адаптера. В коде T обозначает тип возвращаемого значения target и результирующего адаптера. V/v обозначают тип и значение возвращаемого значения filter, которые также присутствуют соответственно в сигнатуре и аргументах target, если только V не равно void. A/a и C/c обозначают типы и значения параметров и аргументов, предшествующих позиции сбора pos в сигнатуре target и следующих за ней. Они также присутствуют в сигнатуре и аргументах результирующего адаптера, где окружают B/b, обозначающие типы параметров и аргументы filter (если они есть).
T target(A...,V,C...);
V filter(B...);
T adapter(A... a,B... b,C... c) {
V v = filter(b...);
return target(a...,v,c...);
}
// and if the filter has no arguments:
T target2(A...,V,C...);
V filter2();
T adapter2(A... a,C... c) {
V v = filter2();
return target2(a...,v,c...);
}
// and if the filter has a void return:
T target3(A...,C...);
void filter3(B...);
T adapter3(A... a,B... b,C... c) {
filter3(b...);
return target3(a...,c...);
}
Адаптер сбора collectArguments(mh, 0, coll) эквивалентен адаптеру, который сначала «сворачивает» затронутые аргументы, а затем отбрасывает их в два отдельных этапа следующим образом:
mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
mh = MethodHandles.foldArguments(mh, coll); //step 1
coll, то collectArguments(mh, 0, coll) эквивалентен filterReturnValue(coll, mh). Если дескриптор метода фильтра coll принимает один аргумент и возвращает результат, отличный от void, то collectArguments(mh, N, coll) эквивалентен filterArguments(mh, N, coll). Возможны и другие эквивалентные варианты, но для них потребуется перестановка аргументов. Примечание: Результирующий адаптер никогда не является дескриптором метода с переменной арностью, даже если исходный целевой дескриптор метода им был.
- Параметры:
-
target— дескриптор метода, вызываемый после фильтрации подпоследовательности аргументов -
pos— позиция первого аргумента адаптера, передаваемого фильтру, и/или аргумента целевого дескриптора, получающего результат фильтра -
filter— дескриптор метода, вызываемый для подпоследовательности аргументов - Возвращает:
- дескриптор метода, включающий указанную логику фильтрации подпоследовательности аргументов
- Вызывает:
-
NullPointerException— если любой из аргументов равен null -
IllegalArgumentException— если тип возвращаемого значенияfilterотличен от void и не совпадает с типом аргументаposцелевого дескриптора, еслиposне находится в диапазоне от 0 до арности целевого дескриптора включительно либо если тип результирующего дескриптора метода будет иметь слишком много параметров - См. также:
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
- См. также:
guardWithTest
public static MethodHandle guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)
Ниже приведен псевдокод результирующего адаптера. В коде T обозначает общий тип результата трех задействованных дескрипторов; A/a — типы и значения параметров и аргументов target, используемых test; а B/b — типы и значения параметров и аргументов target, не используемых test.
boolean test(A...);
T target(A...,B...);
T fallback(A...,B...);
T adapter(A... a,B... b) {
if (test(a...))
return target(a..., b...);
else
return fallback(a..., b...);
}
a... в псевдокоде) не могут быть изменены при выполнении проверки и поэтому передаются от вызывающего к целевому или резервному дескриптору без изменений, в зависимости от ситуации.- Параметры:
-
test— дескриптор метода для проверки, должен возвращать boolean -
target— дескриптор метода, вызываемый, если проверка пройдена -
fallback— дескриптор метода, вызываемый, если проверка не пройдена - Возвращает:
- дескриптор метода, включающий указанную логику if/then/else
- Вызывает:
-
NullPointerException— если любой аргумент равен null -
IllegalArgumentException— еслиtestне возвращает boolean либо если типы всех трех дескрипторов методов не совпадают (с изменением типа возвращаемого значенияtestна соответствующий тип целевого дескриптора).
catchException
public static MethodHandle catchException(MethodHandle target, Class<? extends Throwable> exType, MethodHandle handler)
Целевой дескриптор и обработчик должны иметь одинаковые соответствующие типы аргументов и возвращаемых значений, за исключением того, что обработчик может не принимать конечные аргументы (подобно предикату в guardWithTest). Кроме того, обработчик должен иметь дополнительный начальный параметр типа exType или его суперкласса.
Ниже приведен псевдокод результирующего адаптера. В коде T обозначает тип возвращаемого значения target и handler, а также результирующего адаптера; A/a — типы и значения аргументов результирующего дескриптора, используемых handler; а B/b — типы и значения аргументов результирующего дескриптора, отбрасываемых handler.
T target(A..., B...);
T handler(ExType, A...);
T adapter(A... a, B... b) {
try {
return target(a..., b...);
} catch (ExType ex) {
return handler(ex, a...);
}
}
a... в псевдокоде) не могут быть изменены при выполнении целевого дескриптора и поэтому передаются от вызывающего обработчику без изменений, если обработчик вызывается. Целевой дескриптор и обработчик должны возвращать один и тот же тип, даже если обработчик всегда генерирует исключение. (Так может происходить, например, если обработчик имитирует блок finally.) Чтобы создать такой обработчик, генерирующий исключение, объедините логику его создания с throwException, чтобы создать дескриптор метода с правильным типом возвращаемого значения.
- Параметры:
-
target— вызываемый дескриптор метода -
exType— тип исключения, перехватываемого обработчиком -
handler— дескриптор метода, вызываемый при возникновении соответствующего исключения - Возвращает:
- дескриптор метода, включающий указанную логику try/catch
- Вызывает:
-
NullPointerException— если любой аргумент равен null -
IllegalArgumentException— еслиhandlerне принимает заданный тип исключения либо если типы дескрипторов методов не совпадают по типам возвращаемых значений и соответствующим параметрам - См. также:
throwException
public static MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType)
exType. Дескриптор метода принимает один аргумент типа exType и немедленно генерирует его как исключение. В сигнатуре типа метода формально указывается возвращаемое значение типа returnType. Тип возвращаемого значения может быть любым подходящим: он не влияет на поведение дескриптора метода, поскольку тот никогда не завершится обычным возвратом.- Параметры:
-
returnType— тип возвращаемого значения требуемого дескриптора метода -
exType— тип параметра требуемого дескриптора метода - Возвращает:
- дескриптор метода, способный генерировать заданные исключения
- Вызывает:
-
NullPointerException— если любой из аргументов равен null
loop
public static MethodHandle loop(MethodHandle[]... clauses)
Интуитивно каждый цикл образован одной или несколькими «частями», каждая из которых задает локальную переменную итерации и/или условие выхода из цикла. При каждой итерации цикла выполняется каждая часть по порядку. Часть может обновлять свою переменную итерации; кроме того, она может выполнять проверку и условный выход из цикла. Чтобы выразить эту логику в терминах дескрипторов методов, каждая часть задает до четырех независимых действий:
-
init: инициализация переменной итерации
vтипаVперед выполнением цикла. -
step: при выполнении части — шаг обновления переменной итерации
v. - pred: при выполнении части — вычисление предиката для проверки выхода из цикла.
- fini: если часть приводит к выходу из цикла — выполнение завершающей функции для вычисления возвращаемого значения цикла.
(V...). Сами значения обозначаются как (v...). Говоря о «списках параметров», мы обычно имеем в виду типы, однако в некоторых контекстах (при описании выполнения) списки будут содержать фактические значения. Некоторые части могут быть опущены в соответствии с определенными правилами; в этом случае предусмотрено полезное поведение по умолчанию. Подробное описание приведено ниже.
Параметры необязательны во всех случаях: Каждая функция части может принимать параметр для каждой переменной итерации v, но это не обязательно. Исключение составляют функции init: они не могут принимать параметры v, поскольку эти значения еще не вычислены при выполнении функций init. Любая функция части может не принимать любой конечный подпоследовательный набор параметров, которые она вправе принимать. Фактически любая функция части может вообще не принимать аргументов.
Параметры цикла: Функция части может принимать все значения переменных итерации, которые она вправе принимать, а также дополнительные конечные параметры. Такие дополнительные значения называются параметрами цикла; их типы и значения обозначаются как (A...) и (a...). Они становятся параметрами результирующего дескриптора цикла и передаются при каждом выполнении цикла. (Поскольку функции init не принимают переменные итерации v, любой параметр функции init автоматически является параметром цикла a.) Как и в случае с переменными итерации, функции частей могут принимать параметры цикла, но это не обязательно. Эти параметры цикла являются инвариантными значениями, доступными во всем цикле.
Параметры, доступные повсюду: Каждая функция части, кроме init, может наблюдать все состояние цикла, поскольку ей можно передать полный список (v... a...) текущих значений переменных итерации и входных параметров цикла. Функции init могут наблюдать начальное состояние до цикла в виде (a...). Большинству функций частей не понадобятся все эти сведения, но формально они будут связаны с ними так, как если бы к ним применили dropArguments(MethodHandle, int, List). В частности, обозначением (V*) мы будем выражать произвольный префикс полной последовательности (V...) (и аналогично для (v*), (A*), (a*)). В этих обозначениях общий вид списка параметров функции init — (A*), а общий вид списка параметров функции, отличной от init, — (V*) или (V... A*).
Проверка структуры частей: Для соединения всех частей цикла при заданном наборе частей выполняется ряд проверок и корректировок. Они подробно описаны в следующих шагах. В этих шагах каждое употребление слова «должен» соответствует месту, где будет выброшено исключение IllegalArgumentException, если входные данные комбинатора цикла не удовлетворяют требуемому ограничению.
Эффективно идентичные последовательности: Список параметров A считается эффективно идентичным другому списку параметров B, если A и B идентичны либо если A короче и совпадает с собственным префиксом B. Говоря о неупорядоченном наборе списков параметров, мы считаем, что весь набор «эффективно идентичен», если он содержит самый длинный список и все его элементы эффективно идентичны этому самому длинному списку. Например, любой набор последовательностей типов вида (V*) эффективно идентичен; то же верно, если добавить больше последовательностей вида (V... A*).
Шаг 0: определить структуру частей.
- Массив частей (типа
MethodHandle[][]) не должен бытьnullи должен содержать как минимум один элемент. - Массив частей не может содержать значения
nullили подмассивы длиной больше четырех элементов. - Считается, что части длиной меньше четырех элементов дополнены значениями
nullдо длины четыре. Дополнение выполняется добавлением элементов в конец массива. - Части, состоящие только из значений
null, игнорируются. - Каждая часть рассматривается как кортеж из четырех функций, называемых «init», «step», «pred» и «fini».
Шаг 1A: определить типы переменных итерации (V...).
- Тип переменной итерации для каждой части определяется типами возвращаемых значений функций init и step этой части.
- Если обе функции опущены, у соответствующей части нет переменной итерации (в качестве типа для обозначения этого используется
void). Если одна из функций опущена, тип возвращаемого значения другой функции определяет тип переменной итерации этой части. Если заданы обе функции, общий тип возвращаемого значения (они должны быть идентичны) определяет тип переменной итерации этой части. - Сформировать список типов возвращаемых значений (в порядке частей), исключив все вхождения
void. - Этот список типов называется «типами переменных итерации» (
(V...)).
Шаг 1B: определить параметры цикла (A...).
- Проверить и собрать списки параметров функций init (имеющие вид
(A*)). - Проверить и собрать суффиксы списков параметров функций step, pred и fini после удаления типов переменных итерации. (Они должны иметь вид
(V... A*); следует собирать только части(A*).) - Не собирать суффиксы списков параметров функций step, pred и fini, если они не начинаются со всех типов переменных итерации. (Эти типы будут проверены на шаге 2 вместе со всеми типами функций частей.)
- Опущенные функции частей игнорируются. (Иными словами, считается, что их списки параметров пусты.)
- Все собранные списки параметров должны быть эффективно идентичны.
- Самый длинный список параметров (который обязательно единственный) называется «внешним списком параметров» (
(A...)). - Если такого списка параметров нет, внешний список параметров считается пустой последовательностью.
- Объединенный список, состоящий из типов переменных итерации, за которыми следуют типы внешних параметров, называется «внутренним списком параметров».
Шаг 1C: определить тип возвращаемого значения цикла.
- Проверить типы возвращаемых значений функций 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...)всех параметров цикла.
Пример. Как следует из шага 1A выше, комбинатор loop обладает следующим свойством:
- Заданы
NчастейCn = {null, Sn, Pn}сn = 1..N. - Предположим, что дескрипторы предикатов
Pnлибо являютсяnull, либо не имеют параметров. (Только одинPnдолжен быть не-null.) - Предположим, что дескрипторы шагов
Snимеют сигнатуры(B1..BX)Rnдля некоторого постоянногоX>=N. - Пусть
Q— количество типов, отличных от void,Rn, а(V1...VQ)— последовательность этих типов. - Должно выполняться
Vn == Bnдляn = 1..min(X,Q). - Типы параметров
Vnбудут интерпретироваться как локальные для цикла элементы состояния(V...). - Все оставшиеся типы
BQ+1..BX(еслиQ<X) определяют типы параметров результирующего дескриптора цикла(A...).
(A...) получены из функций step, что естественно, если основная часть вычислений цикла выполняется в шагах. В некоторых циклах основная вычислительная нагрузка может приходиться на функции pred, и тогда этим функциям может потребоваться принимать значения параметров цикла. В циклах со сложной логикой выхода функции fini могут принимать параметры цикла; аналогично, в циклах со сложной логикой входа дополнительные параметры понадобятся функциям init. Поэтому правила определения этих параметров по возможности симметричны для всех частей цикла. В общем случае параметры цикла служат общими инвариантными значениями для всего цикла, а переменные итерации — общими изменяемыми значениями или (если функция step отсутствует) временными внутренними инвариантами цикла. Выполнение цикла.
- При вызове цикла входные значения цикла сохраняются в локальных переменных, чтобы передавать их каждой функции части. Эти локальные переменные инвариантны в цикле.
- Каждая функция init выполняется в порядке частей (с передачей внешних аргументов
(a...)), а значения, отличные отvoid, сохраняются в локальных переменных как переменные итерации(v...). Эти локальные переменные будут изменяться в цикле (если только соответствующие функции step не ведут себя как тождественные функции, как отмечено выше). - Всем функциям, кроме init, передается внутренний список параметров, состоящий из значений переменных итерации, отличных от
void,(v...)(в порядке частей), а затем входных данных цикла(a...)(в порядке аргументов). - Затем функции step и pred выполняются в порядке частей (сначала step, затем pred), пока функция pred не вернет
false. - Результат, отличный от
void, вызова функции step используется для обновления соответствующего значения в последовательности(v...)переменных цикла. Обновленное значение сразу становится доступным всем последующим вызовам функций. - Если функция pred возвращает
false, вызывается соответствующая функция fini, а полученное значение типаRвозвращается как результат всего цикла. - Если все функции pred всегда возвращают true, функции fini никогда не вызываются, и цикл может завершиться только путем выбрасывания исключения.
Советы по использованию.
- Хотя каждая функция step получает текущие значения всех переменных цикла, иногда ей требуется наблюдать только текущее значение собственной переменной. В таком случае функции step может потребоваться явно отбросить все предшествующие переменные цикла. Для этого нужно указать их типы, например в выражении
dropArguments(step, 0, V0.class, ...). - Переменные цикла не обязательно должны изменяться: они могут быть инвариантами цикла. Часть может создать инвариант цикла с помощью подходящей функции init без функций step, pred или fini. Это может пригодиться, чтобы «подключить» входной аргумент цикла к функции step или pred соседней переменной цикла.
- Если некоторые функции частей являются виртуальными методами экземпляра, сам экземпляр удобно поместить в начальную инвариантную «переменную» цикла, используя начальную часть вроде
new MethodHandle[]{identity(ObjType.class)}. В этом случае ссылка на экземпляр будет первым значением переменной итерации, и виртуальные методы будет удобно использовать в качестве частей, поскольку все они будут принимать начальную ссылку на экземпляр, соответствующую этому значению.
V и v обозначают типы и значения переменных цикла; A и a обозначают аргументы, передаваемые всему циклу; а R — общий тип результата всех завершающих функций, а также результирующего цикла.
V... init...(A...);
boolean pred...(V..., A...);
V... step...(V..., A...);
R fini...(V..., A...);
R loop(A... a) {
V... v... = init...(a...);
for (;;) {
for ((v, p, s, f) in (v..., pred..., step..., fini...)) {
v = s(v..., a...);
if (!p(v..., a...)) {
return f(v..., a...);
}
}
}
}
(V...) и (A...) развернуты до полной длины, хотя отдельные функции частей могут не принимать их целиком. Как отмечено выше, недостающие параметры заполняются так, как если бы применялся dropArgumentsToMatch(MethodHandle, int, List, int).- Примечание API:
- Пример: Тот же пример с отбрасыванием аргументов и использованием комбинаторов:
// iterative implementation of the factorial function as a loop handle static int one(int k) { return 1; } static int inc(int i, int acc, int k) { return i + 1; } static int mult(int i, int acc, int k) { return i * acc; } static boolean pred(int i, int acc, int k) { return i < k; } static int fin(int i, int acc, int k) { return acc; } // assume MH_one, MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods // null initializer for counter, should initialize to 0 MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc}; MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin}; MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause); assertEquals(120, loop.invoke(5));Похожий пример, в котором для хранения параметра цикла используется вспомогательный объект:// simplified implementation of the factorial function as a loop handle static int inc(int i) { return i + 1; } // drop acc, k static int mult(int i, int acc) { return i * acc; } //drop k static boolean cmp(int i, int k) { return i < k; } // assume MH_inc, MH_mult, and MH_cmp are handles to the above methods // null initializer for counter, should initialize to 0 MethodHandle MH_one = MethodHandles.constant(int.class, 1); MethodHandle MH_pred = MethodHandles.dropArguments(MH_cmp, 1, int.class); // drop acc MethodHandle MH_fin = MethodHandles.dropArguments(MethodHandles.identity(int.class), 0, int.class); // drop i MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc}; MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin}; MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause); assertEquals(720, loop.invoke(6));// instance-based implementation of the factorial function as a loop handle static class FacLoop { final int k; FacLoop(int k) { this.k = k; } int inc(int i) { return i + 1; } int mult(int i, int acc) { return i * acc; } boolean pred(int i) { return i < k; } int fin(int i, int acc) { return acc; } } // assume MH_FacLoop is a handle to the constructor // assume MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods // null initializer for counter, should initialize to 0 MethodHandle MH_one = MethodHandles.constant(int.class, 1); MethodHandle[] instanceClause = new MethodHandle[]{MH_FacLoop}; MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc}; MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin}; MethodHandle loop = MethodHandles.loop(instanceClause, counterClause, accumulatorClause); assertEquals(5040, loop.invoke(7)); - Параметры:
-
clauses— массив массивов (кортежей из четырех элементов) с элементами типаMethodHandle, удовлетворяющими описанным выше правилам. - Возвращает:
- дескриптор метода, реализующий поведение цикла, определенное аргументами.
- Исключения:
-
IllegalArgumentException— если нарушено какое-либо из описанных выше ограничений. - Начиная с версии:
- 9
- См. также:
whileLoop
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
- См. также:
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
- См. также:
countedLoop
public static MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body)
Число итераций определяется результатом вычисления дескриптора iterations. Счетчик цикла i — это дополнительная переменная итерации цикла типа int. Она инициализируется значением 0 и увеличивается на 1 в каждой итерации.
Если дескриптор body возвращает тип void, отличный от V, также присутствует ведущая переменная итерации цикла этого типа. Эта переменная инициализируется с помощью необязательного дескриптора init либо значением по умолчанию типа V, если этот дескриптор равен null.
В каждой итерации переменные итерации передаются при вызове дескриптора body. Возвращаемое телом цикла значение типа V, отличное от void, обновляет ведущую переменную итерации. Результатом выполнения дескриптора цикла будет итоговое значение V этой переменной (или void, если переменная V отсутствует).
Для дескрипторов-аргументов действуют следующие правила:
- Дескриптор
iterationsне должен бытьnullи должен возвращать типint, далее обозначаемый какIв списках типов параметров. - Дескриптор
bodyне должен бытьnull; его тип должен иметь вид(V I A...)V, гдеV— тип, отличный отvoid, либо(I A...)void. (В случаеvoidмы присваиваем типvoidимениVи будем записывать(V I A...)V, подразумевая, что тип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
public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body)
Счетчик цикла i — это переменная итерации цикла типа int. Дескрипторы start и end задают начальное (включительно) и конечное (исключительно) значения счетчика цикла. Счетчик цикла инициализируется значением int, возвращенным при вычислении дескриптора start, и увеличивается до значения, возвращенного дескриптором end (не включая его), с шагом 1.
Если дескриптор body возвращает тип void, отличный от V, также присутствует ведущая переменная итерации цикла этого типа. Эта переменная инициализируется с помощью необязательного дескриптора init либо значением по умолчанию типа V, если этот дескриптор равен null.
В каждой итерации переменные итерации передаются при вызове дескриптора body. Возвращаемое телом цикла значение типа V, отличное от void, обновляет ведущую переменную итерации. Результатом выполнения дескриптора цикла будет итоговое значение V этой переменной (или void, если переменная V отсутствует).
Для дескрипторов-аргументов действуют следующие правила:
- Дескрипторы
startиendне должны бытьnullи должны оба возвращать общий типint, далее обозначаемый какIв списках типов параметров. - Дескриптор
bodyне должен бытьnull; его тип должен иметь вид(V I A...)V, гдеV— тип, отличный отvoid, либо(I A...)void. (В случаеvoidмы присваиваем типvoidимениVи будем записывать(V I A...)V, подразумевая, что тип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
- См. также:
iteratedLoop
public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body)
Iterator<T>. Это удобная обертка для универсального комбинатора циклов. Сам итератор определяется при вычислении дескриптора iterator. Каждое полученное им значение сохраняется в переменной итерации цикла типа T.
Если дескриптор body возвращает тип void, отличный от V, также присутствует ведущая переменная итерации цикла этого типа. Эта переменная инициализируется с помощью необязательного дескриптора init либо значением по умолчанию типа V, если этот дескриптор равен null.
В каждой итерации переменные итерации передаются при вызове дескриптора body. Возвращаемое телом цикла значение типа V, отличное от void, обновляет ведущую переменную итерации. Результатом выполнения дескриптора цикла будет итоговое значение V этой переменной (или void, если переменная V отсутствует).
Для дескрипторов-аргументов действуют следующие правила:
- Дескриптор
bodyне должен бытьnull; его тип должен иметь вид(V T A...)V, гдеV— тип, отличный отvoid, либо(T A...)void. (В случаеvoidмы присваиваем типvoidимениVи будем записывать(V T A...)V, подразумевая, что тип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
- См. также:
tableSwitch
public static MethodHandle tableSwitch(MethodHandle fallback, MethodHandle... targets)
Если значение селектора равно n, где n находится в диапазоне [0, N), а N — это число целевых дескрипторов метода, дескриптор метода табличного переключения вызовет n-й целевой дескриптор метода из списка целевых дескрипторов.
Если значение селектора не входит в диапазон [0, N), дескриптор метода табличного переключения вызовет заданный резервный дескриптор метода.
Все передаваемые этому методу дескрипторы метода должны иметь одинаковый тип; кроме того, их ведущий параметр должен иметь тип int. Ведущий параметр представляет селектор.
Все завершающие параметры, присутствующие в типе, также будут присутствовать в возвращаемом дескрипторе метода табличного переключения. Значения, переданные этим параметрам, будут пересылаться вместе со значением селектора выбранному дескриптору метода при его вызове.
- Примечание API:
- Пример: в каждом случае отбрасывается полученное значение
selectorи принимается дополнительный аргументString, который объединяется (с помощьюString.concat(String)) с постоянной строкой-меткой, заданной для этого случая:MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle caseMh = lookup.findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class)); caseMh = MethodHandles.dropArguments(caseMh, 0, int.class); MethodHandle caseDefault = MethodHandles.insertArguments(caseMh, 1, "default: "); MethodHandle case0 = MethodHandles.insertArguments(caseMh, 1, "case 0: "); MethodHandle case1 = MethodHandles.insertArguments(caseMh, 1, "case 1: "); MethodHandle mhSwitch = MethodHandles.tableSwitch( caseDefault, case0, case1 ); assertEquals("default: data", (String) mhSwitch.invokeExact(-1, "data")); assertEquals("case 0: data", (String) mhSwitch.invokeExact(0, "data")); assertEquals("case 1: data", (String) mhSwitch.invokeExact(1, "data")); assertEquals("default: data", (String) mhSwitch.invokeExact(2, "data")); - Параметры:
-
fallback— резервный дескриптор метода, вызываемый, если селектор не входит в диапазон[0, N). -
targets— массив целевых дескрипторов метода. - Возвращает:
- дескриптор метода табличного переключения.
- Вызывает:
-
NullPointerException— еслиfallback, массивtargetsили какой-либо элемент массиваtargetsравенnull. -
IllegalArgumentException— если массивtargetsпуст, если ведущий параметр резервного дескриптора или любого целевого дескриптора не имеет типintлибо если типы резервного дескриптора и всех целевых дескрипторов различаются. - С версии:
- 17
filterValue
public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
При вызове, например, VarHandle.set(Object...) для полученного var handle входящее значение (типа T, где T — последний тип параметра первой функции-фильтра) обрабатывается первым фильтром, а затем передаётся целевому var handle. И наоборот, при вызове, например, VarHandle.get(Object...) для полученного var handle возвращаемое значение, полученное от целевого var handle (типа T, где T — последний тип параметра второй функции-фильтра), обрабатывается вторым фильтром и возвращается вызывающему коду. Более сложные типы режимов доступа, такие как VarHandle.AccessMode.COMPARE_AND_EXCHANGE, могут применять оба фильтра одновременно.
Чтобы фильтры упаковки и распаковки были корректно сформированы, их типы должны иметь вид (A... , S) -> T и (A... , T) -> S соответственно, где T — тип целевого var handle. В этом случае полученный var handle будет иметь тип S и дополнительные координаты A... (которые будут добавлены к координатам целевого var handle).
Если при вызове фильтры упаковки и распаковки выбросят проверяемые исключения, полученный var handle выбросит IllegalStateException.
Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.
- Параметры:
-
target— целевой var handle -
filterToTarget— фильтр для преобразования типаSв типtarget -
filterFromTarget— фильтр для преобразования типаtargetв типS - Возвращает:
- адаптер var handle, принимающий новый тип и выполняющий указанные преобразования упаковки/распаковки.
- Выбрасывает:
-
IllegalArgumentException— еслиfilterFromTargetиfilterToTargetсформированы некорректно, то есть имеют типы, отличные от(A... , S) -> Tи(A... , T) -> Sсоответственно, гдеT— тип целевого var handle, либо если установлено, чтоfilterFromTargetилиfilterToTargetвыбрасывает проверяемые исключения. -
NullPointerException— если любой из аргументов равенnull. - Начиная с версии:
- 22
filterCoordinates
public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters)
При вызове, например, VarHandle.get(Object...) для полученного var handle входящие значения координат, начиная с позиции pos (типа C1, C2 ... Cn, где C1, C2 ... Cn — типы возвращаемых значений унарных функций-фильтров), преобразуются в новые значения (типа S1, S2 ... Sn, где S1, S2 ... Sn — типы параметров унарных функций-фильтров), а затем передаются целевому var handle вместе с координатами, не изменёнными при адаптации.
Чтобы фильтры координат были корректно сформированы, их типы должны иметь вид S1 -> T1, S2 -> T1 ... Sn -> Tn, где T1, T2 ... Tn — типы координат целевого var handle, начиная с позиции pos.
Если при вызове какой-либо фильтр выбросит проверяемое исключение, полученный var handle выбросит IllegalStateException.
Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.
- Параметры:
-
target— целевой var handle -
pos— позиция первой преобразуемой координаты -
filters— унарные функции для преобразования координат, начиная с позицииpos - Возвращает:
- адаптер var handle, принимающий новые типы координат и применяющий указанное преобразование к новым значениям координат.
- Выбрасывает:
-
IllegalArgumentException— если дескрипторы вfiltersсформированы некорректно, то есть имеют типы, отличные отS1 -> T1, S2 -> T2, ... Sn -> Tn, гдеT1, T2 ... Tn— типы координат целевого var handle, начиная с позицииpos, еслиposне находится в диапазоне от 0 до арности координат целевого var handle включительно, если фильтров больше, чем доступных типов координат, начиная сpos, либо если установлено, что какой-либо из фильтров выбрасывает проверяемые исключения. -
NullPointerException— если любой из аргументов равенnullилиfiltersсодержитnull. - Начиная с версии:
- 22
insertCoordinates
public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values)
При вызове, например, VarHandle.get(Object...) для полученного var handle входящие значения координат объединяются со связанными значениями координат, а затем передаются целевому var handle.
Чтобы связанные координаты были корректно сформированы, их типы должны быть T1, T2 ... Tn , где T1, T2 ... Tn — типы координат целевого var handle, начиная с позиции pos.
Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.
- Параметры:
-
target— var handle, вызываемый после вставки связанных координат -
pos— позиция первой вставляемой координаты -
values— последовательность вставляемых связанных координат - Возвращает:
- адаптер var handle, вставляющий дополнительные координаты перед вызовом целевого var handle
- Выбрасывает:
-
IllegalArgumentException— еслиposне находится в диапазоне от 0 до арности координат целевого var handle включительно либо если предоставлено больше значений, чем доступных типов координат, начиная сpos. -
ClassCastException— если связанные координаты вvaluesсформированы некорректно, то есть имеют типы, отличные отT1, T2 ... Tn, гдеT1, T2 ... Tn— типы координат целевого var handle, начиная с позицииpos. -
NullPointerException— если любой из аргументов равенnullилиvaluesсодержитnull. - Начиная с версии:
- 22
permuteCoordinates
public static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder)
Порядок перестановки задаётся переданным массивом. Обозначим #I количество входящих координат (значение newCoordinates.size()), а #O — количество исходящих координат (количество координат целевого var handle). Тогда длина массива перестановки должна быть равна #O, а каждый его элемент должен быть неотрицательным числом, меньшим #I. Для каждого N, меньшего #O, N-я исходящая координата будет взята из I-й входящей координаты, где I равно reorder[N].
Преобразования типов координат не выполняются. Тип каждой входящей координаты, определяемый с помощью newCoordinates, должен совпадать с типом соответствующей исходящей координаты целевого var handle.
Массив перестановки не обязательно должен задавать настоящую перестановку. Входящая координата будет продублирована, если её индекс встречается в массиве более одного раза, и отброшена, если её индекс в массиве отсутствует.
Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.
- Параметры:
-
target— var handle, вызываемый после перестановки координат -
newCoordinates— новые типы координат -
reorder— массив индексов, задающий порядок перестановки - Возвращает:
- адаптер var handle, переставляющий входящие значения координат перед вызовом целевого var handle
- Выбрасывает:
-
IllegalArgumentException— если длина массива индексов не равна количеству координат целевого var handle, если какой-либо элемент массива индексов не является допустимым индексом координаты дляnewCoordinatesлибо если типы соответствующих координат в целевом var handle и вnewCoordinatesне совпадают. -
NullPointerException— если любой из аргументов равенnullилиnewCoordinatesсодержитnull. - Начиная с версии:
- 22
collectCoordinates
public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter)
Если R — тип возвращаемого значения фильтра, то:
- если
Rне являетсяvoid, целевой var handle должен иметь координату типаRв позицииpos. Типы параметров фильтра заменят тип координаты в позицииposцелевого var handle. При вызове возвращённого var handle фильтр сначала вызывается, а его результат передаётся вместо координаты в позицииposпри последующем вызове целевого var handle. - если
Rявляетсяvoid, типы параметров фильтра (если они есть) будут вставлены в список типов координат целевого var handle в позицииpos. В этом случае при вызове возвращённого var handle фильтр фактически выполняет побочное действие: принимает некоторые значения координат, после чего происходит последующий вызов целевого var handle.
Если при вызове какой-либо фильтр выбросит проверяемое исключение, полученный var handle выбросит IllegalStateException.
Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.
- Параметры:
-
target— var handle, вызываемый после фильтрации координат -
pos— позиция в списке координат целевого var handle, в которую вставляется фильтр -
filter— дескриптор метода-фильтра - Возвращает:
- адаптер var handle, фильтрующий входящие значения координат перед вызовом целевого var handle
- Выбрасывает:
-
IllegalArgumentException— если возвращаемый типfilterне равен void и не совпадает с типомpos-й координаты целевого var handle, еслиposне находится в диапазоне от 0 до арности координат целевого var handle включительно, если тип полученного var handle содержит слишком много координат либо если установлено, чтоfilterвыбрасывает проверяемые исключения. -
NullPointerException— если любой из аргументов равенnull. - Начиная с версии:
- 22
dropCoordinates
public static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes)
Значение аргумента pos может находиться в диапазоне от нуля до N, где N — арность типов координат целевого var handle. Если pos равно нулю, фиктивные координаты будут предшествовать реальным аргументам целевого var handle; если pos равно N, они будут следовать за ними.
Полученный var handle будет поддерживать те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой var handle.
- Параметры:
-
target— var handle, вызываемый после отбрасывания фиктивных координат -
pos— позиция первой отбрасываемой координаты (ноль для самой левой) -
valueTypes— тип или типы отбрасываемых координат - Возвращает:
- адаптер var handle, отбрасывающий некоторые фиктивные координаты перед вызовом целевого var handle
- Выбрасывает:
-
IllegalArgumentException— еслиposне находится в диапазоне от 0 до арности координат целевого var handle включительно. -
NullPointerException— если любой из аргументов равенnullилиvalueTypesсодержитnull. - Начиная с версии:
- 22
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/invoke/MethodHandles.html