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