Класс 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 |
Предварительный просмотр. Адаптирует целевой обработчик переменных, предварительно обрабатывая подпоследовательность значений его координат с помощью фильтра (обработчика метода). |
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 |
Предварительный просмотр. Возвращает обработчик переменных, который отбросит некоторые фиктивные координаты перед делегированием целевому обработчику переменных. |
static MethodHandle |
dropReturn |
Отбрасывает значение возврата целевого обработчика (если оно есть). |
static MethodHandle |
empty |
Создаёт обработчик метода запрошенного типа, который игнорирует все аргументы, ничего не делает и возвращает подходящее значение по умолчанию в зависимости от типа возврата. |
static MethodHandle |
exactInvoker |
Создаёт специальный обработчик метода-вызывателя, который может использоваться для вызова любого обработчика метода данного типа, как если бы это делалось с помощью invokeExact. |
static MethodHandle |
explicitCastArguments |
Создаёт обработчик метода, адаптирующий тип данного обработчика метода к новому типу путём парной конверсии аргументов и типа возврата. |
static MethodHandle |
filterArguments |
Адаптирует целевой обработчик метода, предварительно обрабатывая один или несколько его аргументов с помощью собственной функции фильтрации, и затем вызывая целевой обработчик с заменой каждого предварительно обработанного аргумента результатом его соответствующей функции фильтрации. |
static VarHandle |
filterCoordinates |
Предварительный просмотр. Адаптирует целевой обработчик переменных путём предварительной обработки входящих значений координат с использованием функций фильтрации. |
static MethodHandle |
filterReturnValue |
Адаптирует целевой обработчик метода, пост-обрабатывая его возвращаемое значение (если таковое имеется) с помощью фильтра (другой обработчик метода). |
static VarHandle |
filterValue |
Предварительный просмотр. Адаптирует целевой обработчик переменных, предварительно обрабатывая входящие и исходящие значения с помощью пары функций фильтрации. |
static MethodHandle |
foldArguments |
Адаптирует целевой обработчик метода, предварительно обрабатывая некоторые из его аргументов, начиная с заданной позиции, и затем вызывая целевой обработчик с результатом предварительной обработки, вставленным в исходную последовательность аргументов непосредственно перед сложенными аргументами. |
static MethodHandle |
foldArguments |
Адаптирует целевой обработчик метода, предварительно обрабатывая некоторые из его аргументов, и затем вызывая целевой обработчик с результатом предварительной обработки, вставленным в исходную последовательность аргументов. |
static MethodHandle |
guardWithTest |
Создаёт обработчик метода, адаптирующий целевой обработчик метода, защищая его с помощью теста, обработчика булевого значения. |
static MethodHandle |
identity |
Создаёт обработчик метода, который возвращает свой единственный аргумент при вызове. |
static MethodHandle |
insertArguments |
Предоставляет целевому обработчику метода один или несколько связанных аргументов заранее перед вызовом обработчика метода. |
static VarHandle |
insertCoordinates |
Предварительный просмотр. Предоставляет целевому обработчику переменных один или несколько связанных координат заранее перед вызовом обработчика переменных. |
static MethodHandle |
invoker |
Создаёт специальный обработчик метода-вызывателя, который может использоваться для вызова любого обработчика метода, совместимого с заданным типом, как если бы это делалось с помощью invoke. |
static MethodHandle |
iteratedLoop |
Создаёт цикл, перебирающий значения, производимые Iterator<T>. |
static MethodHandles.Lookup |
lookup() |
Возвращает lookup object с полными возможностями эмуляции всех поддерживаемых байткодовых поведений вызывающего кода. |
static MethodHandle |
loop |
Создаёт обработчик метода, представляющий цикл с несколькими переменными цикла, которые обновляются и проверяются на каждой итерации. |
static VarHandle |
memorySegmentViewVarHandle |
Предварительный просмотр. Создаёт объект обработчика переменных, который может использоваться для декодирования сегмента памятиПРЕДПРОСМОТР по заданному байтовому смещению, используя предоставленное расположение значения. |
static MethodHandle |
permuteArguments |
Создаёт обработчик метода, адаптирующий последовательность вызовов данного обработчика метода к новому типу путём переупорядочения аргументов. |
static VarHandle |
permuteCoordinates |
Предварительный просмотр. Предоставляет обработчик переменных, который адаптирует значения координат целевого обработчика переменных, переупорядочивая их таким образом, чтобы новые координаты соответствовали предоставленным. |
static MethodHandles.Lookup |
privateLookupIn |
Возвращает объект lookup на целевом классе, чтобы эмулировать все поддерживаемые байткодовые поведения, включая доступ к частным методам. |
static MethodHandles.Lookup |
publicLookup() |
Возвращает lookup object, которому доверяют минимально. |
static <T extends Member> |
reflectAs |
Выполняет необработанный "разрыв" прямого обработчика метода прямого обработчика метода. |
static MethodHandle |
spreadInvoker |
Создаёт обработчик метода, который будет вызывать любой обработчик метода заданного type, при этом заданное количество хвостовых аргументов будет заменено на один хвостовой массив Object[]. |
static MethodHandle |
tableSwitch |
Создаёт обработчик метода переключателя таблицы, который можно использовать для переключения между набором целевых обработчиков методов на основе заданного целевого индекса, называемого селектором. |
static MethodHandle |
throwException |
Создаёт обработчик метода, который будет выбрасывать исключения заданного exType. |
static MethodHandle |
tryFinally |
Создаёт обработчик метода, который адаптирует обработчик метода target, обернув его в блок try-finally. |
static MethodHandle |
varHandleExactInvoker |
Создаёт специальный обработчик вызова метода, который может быть использован для вызова метода с полиморфной сигнатурой доступа к любому VarHandle, тип режима доступа которого совместим с заданным типом. |
static MethodHandle |
varHandleInvoker |
Создаёт специальный обработчик вызова метода, который может быть использован для вызова метода с полиморфной сигнатурой доступа к любому VarHandle, тип режима доступа которого совместим с заданным типом. |
static MethodHandle |
whileLoop |
Строит цикл while из инициализатора, тела и предиката. |
static MethodHandle |
zero |
Создаёт постоянный обработчик метода запрошенного типа возврата, который возвращает значение по умолчанию для этого типа каждый раз при вызове. |
Подробное описание методов
lookup
public static MethodHandles.Lookup lookup()
lookup object с полными возможностями для эмуляции всех поддерживаемых поведенческих особенностей байткода вызывающего объекта. Эти возможности включают полный доступ с привилегиями к вызывающему объекту. Методы-фабрики объекта lookup могут создавать прямые обработчики метода для любого члена, к которому вызывающий объект имеет доступ через байткод, включая защищённые и частные поля и методы. Данный объект lookup создан исходным классом lookup и имеет установленный бит ORIGINAL. Данный объект lookup представляет собой возможность, которая может быть делегирована доверенным агентам. Не храните его в местах, где к нему может получить доступ недоверенный код. Данный метод чувствителен к вызывающему объекту, что означает, что он может возвращать разные значения различным вызывающим объектам. В тех случаях, когда MethodHandles.lookup вызывается из контекста, где нет кадра вызова в стеке (например, при прямом вызове из присоединённого к JNI потока), IllegalCallerException выбрасывается. Чтобы получить lookup object в таком контексте, используйте вспомогательный класс, который будет неявно определён как вызывающий, или используйте publicLookup() для получения менее привилегированного lookup.
- Возвращает:
- объект lookup для вызывающего объекта данного метода с исходным и полным доступом с привилегиями.
- Выбрасывает:
-
IllegalCallerException- если в стеке нет кадра вызова.
publicLookup
public static MethodHandles.Lookup publicLookup()
lookup object, которому доверяют минимально. У lookup есть режим UNCONDITIONAL. Он может быть использован только для создания обработчиков метода для публичных членов публичных классов в пакетах, которые экспортированы безусловно. В соответствии с соглашениями, классом lookup данного объекта lookup будет Object.
- Примечание API:
- Использование Object является традиционным, и поскольку режимы lookup ограничены, нет особого доступа к внутренностям Object, его пакету или модулю. Этот публичный объект lookup или другой объект lookup с режимом
UNCONDITIONALпредполагает читаемость. Следовательно, класс lookup не используется для определения контекста lookup.Обсуждение: Класс lookup можно изменить на любой другой класс
C, используя выражение видаpublicLookup().in(C.class). Объект публичного lookup всегда подчиняется проверкам системного менеджера безопасности security manager checks. Также он не может получить доступ к методам, чувствительным к вызывающему объекту. - Возвращает:
- объект lookup, которому доверяют минимально
privateLookupIn
public static MethodHandles.Lookup privateLookupIn(Class<?> targetClass, MethodHandles.Lookup caller) throws IllegalAccessException
lookup объект для целевого класса для эмуляции всех поддерживаемых поведенческих особенностей байткода, включая приватный доступ. Возвращаемый объект lookup может предоставлять доступ к классам в модулях и пакетах, а также к членам этих классов, за пределами обычных правил доступа Java, вместо соответствия более либеральным правилам для модульного глубокого рефлексирования. Вызывающий объект, указанный как объект Lookup, в модуле M1, разрешено выполнять глубокое рефлексирование модуля M2 и пакета целевого класса, если и только если все следующие условия выполняются true:
- Если существует системный менеджер безопасности, его метод
checkPermissionвызывается для проверкиReflectPermission("suppressAccessChecks"), и он должен возвратить результат без исключений. - Объект 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:
- Объект
Lookup, возвращаемый данным методом, может определять классы в пакете runtimetargetClass. Следует проявлять особую осторожность при открытии пакета для другого модуля, так как определённые таким образом классы имеют такой же полный доступ с привилегиями, как и другие члены модуляtargetClass. - Параметры:
-
targetClass- целевой класс -
caller- объект lookup вызывающего объекта - Возвращает:
- объект lookup для целевого класса с приватным доступом
- Выбрасывает:
-
IllegalArgumentException- еслиtargetClassявляется примитивным типом, void или классом массива -
NullPointerException- еслиtargetClassилиcallerявляютсяnull -
SecurityException- если запрещено системным менеджером безопасности -
IllegalAccessException- если любая из других проверок доступа, указанных выше, терпит неудачу - С:
- 9
- См. также:
classData
public static <T> T classData(MethodHandles.Lookup caller, String name, Class<T> type) throws IllegalAccessException
caller, или null. Скрытый класс с данными класса можно создать, вызвав Lookup::defineHiddenClassWithClassData. Этот метод вызовет инициализатор статического класса класса поиска заданного объекта поиска caller, если он ещё не был инициализирован.
Скрытый класс, созданный с помощью Lookup::defineHiddenClass, и нескрытые классы не имеют данных класса. null возвращается, если этот метод вызывается для объекта поиска для этих классов.
Режимы поиска (lookup modes) для этого поиска должны иметь оригинальный доступ для получения данных класса.
- API Note:
- Этот метод может быть вызван как метод загрузки для динамически вычисляемой константы. Фреймворк может создать скрытый класс с данными класса, например, который может быть
ClassилиMethodHandleобъектом. Данные класса доступны только для объекта поиска, созданного исходным вызывающим объектом, но недоступны для других членов в том же вложенном блоке. Если фреймворк передает чувствительные к безопасности объекты скрытому классу через данные класса, рекомендуется загрузить значение данных класса как динамически вычисляемую константу вместо хранения данных класса в частном(ых) статическом(их) поле(ях), которые доступны другим членам в том же вложенном блоке. - Type Parameters:
-
T- тип для приведения объекта данных класса - Parameters:
-
caller- контекст поиска, описывающий класс, выполняющий операцию (обычно стекируется JVM) -
name- должен бытьConstantDescs.DEFAULT_NAME("_") -
type- тип данных класса - Returns:
- значение данных класса, если оно присутствует в классе поиска; в противном случае
null - Throws:
-
IllegalArgumentException- если имя не"_" -
IllegalAccessException- если контекст поиска не имеет оригинального доступа -
ClassCastException- если данные класса не могут быть приведены к заданному типуtype -
NullPointerException- еслиcallerилиtypeаргументnull - See Java Virtual Machine Specification:
- 5.5 Инициализация
- Since:
- 16
- See Also:
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....), содержащий более одного объекта, и использовать этот метод для загрузки одного элемента по определенному индексу. Данные класса доступны только для объекта поиска, созданного исходным вызывающим объектом, но недоступны для других членов в том же вложенном блоке. Если фреймворк передает чувствительные к безопасности объекты скрытому классу через данные класса, рекомендуется загрузить значение данных класса как динамически вычисляемую константу вместо хранения данных класса в частном(ых) статическом(их) поле(ях), которые доступны другим членам в том же вложенном блоке. - Type Parameters:
-
T- тип для приведения результата - Parameters:
-
caller- контекст поиска, описывающий класс, выполняющий операцию (обычно стекируется JVM) -
name- должен бытьConstantDescs.DEFAULT_NAME("_") -
type- тип элемента по указанному индексу в данных класса -
index- индекс элемента в данных класса - Returns:
- элемент по указанному индексу в данных класса, если данные класса присутствуют; в противном случае
null - Throws:
-
IllegalArgumentException- если имя не"_" -
IllegalAccessException- если контекст поиска не имеет оригинального доступа -
ClassCastException- если данные класса не могут быть приведены к типуListили элемент по указанному индексу не может быть приведен к заданному типу -
IndexOutOfBoundsException- если индекс находится вне диапазона -
NullPointerException- еслиcallerилиtypeаргументnull; или если операция unboxing завершается неудачей, потому что элемент по указанному индексуnull - Since:
- 16
- See Also:
reflectAs
public static <T extends Member> T reflectAs(Class<T> expected, MethodHandle target)
Lookup.revealDirect на целевом, чтобы получить его символическую ссылку, и затем вызвал MethodHandleInfo.reflectAs для разрешения символической ссылки на член. Если существует менеджер безопасности, его метод checkPermission вызывается с разрешением ReflectPermission("suppressAccessChecks").
- Type Parameters:
-
T- желаемый тип результата, либоMember, или подтип - Parameters:
-
expected- объект класса, представляющий желаемый тип результатаT -
target- прямой обработчик метода для раскрытия компонентов символической ссылки - Returns:
- ссылка на метод, конструктор или поле
- Throws:
-
SecurityException- если вызывающий не имеет привилегий для вызоваsetAccessible -
NullPointerException- если любой из аргументовnull -
IllegalArgumentException- если целевой объект не является прямым обработчиком метода -
ClassCastException- если член не имеет ожидаемого типа - Since:
- 1.8
arrayConstructor
public static MethodHandle arrayConstructor(Class<?> arrayClass) throws IllegalArgumentException
anewarray байт-кода. Тип возвращаемого значения обработчика метода будет типом массива. Тип его единственного аргумента будет int, который указывает размер массива. Если возвращаемый обработчик метода вызывается с отрицательным размером массива, будет брошено исключение NegativeArraySizeException.
- Parameters:
-
arrayClass- тип массива - Returns:
- обработчик метода, который может создавать массивы заданного типа
- Throws:
-
NullPointerException- если аргументnull -
IllegalArgumentException- еслиarrayClassне является типом массива - See Java Virtual Machine Specification:
- 6.5 Инструкция
anewarray
- Since:
- 9
- See Also:
arrayLength
public static MethodHandle arrayLength(Class<?> arrayClass) throws IllegalArgumentException
arraylength байткода. Тип обработчика метода будет иметь int в качестве типа возвращаемого значения, а его единственным аргументом будет тип массива. Если возвращаемый обработчик метода вызывается с ссылкой на массив null, будет брошено исключение NullPointerException.
- Parameters:
-
arrayClass- тип массива - Returns:
- обработчик метода, который может извлечь длину массива заданного типа массива
- Throws:
-
NullPointerException- если аргумент являетсяnull -
IllegalArgumentException- если arrayClass не является типом массива - См. Спецификацию виртуальной машины Java:
- 6.5
arraylengthИнструкция
- Since:
- 9
arrayElementGetter
public static MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException
aaload байткода. Тип обработчика метода будет иметь тип элемента массива в качестве типа возвращаемого значения. Его первый аргумент будет типом массива, а второй будет int. При вызове возвращаемого обработчика метода, ссылка на массив и индекс массива проверяются. Будет брошено исключение NullPointerException, если ссылка на массив является null, и будет брошено исключение ArrayIndexOutOfBoundsException, если индекс отрицательный или если он больше или равен длине массива.
- Parameters:
-
arrayClass- тип массива - Returns:
- обработчик метода, который может загружать значения из заданного типа массива
- Throws:
-
NullPointerException- если аргумент равен null -
IllegalArgumentException- если arrayClass не является типом массива - См. Спецификацию виртуальной машины Java:
- 6.5
aaloadИнструкция
arrayElementSetter
public static MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException
astore байткода. Тип обработчика метода будет иметь тип void. Его последний аргумент будет типом элемента массива. Первые два аргумента будут типом массива и int. При вызове возвращаемого обработчика метода, ссылка на массив и индекс массива проверяются. Будет брошено исключение NullPointerException, если ссылка на массив равна null, и будет брошено исключение ArrayIndexOutOfBoundsException, если индекс отрицательный или если он больше или равен длине массива.
- Parameters:
-
arrayClass- класс массива - Returns:
- обработчик метода, который может сохранять значения в массив заданного типа
- Throws:
-
NullPointerException- если аргумент равен null -
IllegalArgumentException- если arrayClass не является типом массива - См. Спецификацию виртуальной машины Java:
- 6.5
aastoreИнструкция
arrayElementVarHandle
public static VarHandle arrayElementVarHandle(Class<?> arrayClass) throws IllegalArgumentException
arrayClass. Тип переменной VarHandle - это тип компонента arrayClass, а список типов координат - (arrayClass, int), где тип координаты int соответствует аргументу, являющемуся индексом в массиве. Некоторые режимы доступа возвращаемого VarHandle не поддерживаются в следующих условиях:
- если тип компонента отличается от
byte,short,char,int,long,floatилиdouble, то атомарные режимы числовых обновлений не поддерживаются. - если тип компонента отличается от
boolean,byte,short,char,intилиlong, то атомарные режимы битовых обновлений не поддерживаются.
Если тип компонента является float или double, то режимы числового и атомарного обновления сравнивают значения, используя их битовое представление (см. Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double) соответственно).
При вызове возвращаемого VarHandle, ссылка на массив и индекс массива проверяются. Будет брошено исключение NullPointerException, если ссылка на массив равна null, и будет брошено исключение 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.
Обращение к байтам по индексу может быть выровнено или не выровнено для T относительно базового адреса памяти, A, связанного с массивом и индексом. Если доступ не выровнен, доступ для любого режима, кроме get и set, приведет к исключению IllegalStateException. В таких случаях атомарный доступ гарантирован только относительно наибольшей степени двойки, которая делит НОД A и размер (в байтах) T. Если доступ выровнен, поддерживаются следующие режимы доступа, гарантирующие атомарный доступ:
- Режимы чтения-записи для всех
T, за исключением режимов доступаgetиsetдляlongиdoubleна 32-битных платформах. - Режимы атомарного обновления для
int,long,floatилиdouble. (Будущие основные релизы JDK могут поддерживать дополнительные типы для некоторых в настоящее время неподдерживаемых режимов доступа.) - Числовые режимы атомарного обновления для
intиlong. (Будущие основные релизы JDK могут поддерживать дополнительные числовые типы для некоторых в настоящее время неподдерживаемых режимов доступа.) - Битовые режимы атомарного обновления для
intиlong. (Будущие основные релизы JDK могут поддерживать дополнительные числовые типы для некоторых в настоящее время неподдерживаемых режимов доступа.)
Невыровненный доступ, а следовательно, и гарантии атомности, могут быть определены для массивов byte[] без работы с конкретным массивом. Учитывая index, T и его соответствующий упакованный тип, T_BOX, невыравнивание может быть определено следующим образом:
int sizeOfT = T_BOX.BYTES; // size in bytes of T
int misalignedAtZeroIndex = ByteBuffer.wrap(new byte[0]).
alignmentOffset(0, sizeOfT);
int misalignedAtIndex = (misalignedAtZeroIndex + index) % sizeOfT;
boolean isMisaligned = misalignedAtIndex != 0;
Если тип переменной — float или double, то режимы атомарного обновления сравнивают значения с использованием их битового представления (см. Float.floatToRawIntBits(float) и Double.doubleToRawLongBits(double) соответственно).
- Параметры:
-
viewArrayClass- класс массива представления, с компонентным типом типаT -
byteOrder- порядок байтов элементов массива представления, как хранится в базовом массивеbyte - Возвращает:
- VarHandle, обеспечивающий доступ к элементам массива
byte[], рассматриваемого как массив элементов, соответствующих типу компонента класса массива представления - Исключение:
-
NullPointerException- если viewArrayClass или byteOrder равно null -
IllegalArgumentException- если viewArrayClass не является типом массива -
UnsupportedOperationException- если компонентный тип viewArrayClass не поддерживается как тип переменной - С момента:
- 9
byteBufferViewVarHandle
public static VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass, ByteOrder byteOrder) throws IllegalArgumentException
ByteBuffer, рассматриваемого как массив элементов другого примитивного компонентного типа, отличного от byte, такого как int[] или long[]. Тип переменной VarHandle — это компонентный тип viewArrayClass, а список типов координат — (ByteBuffer, int), где тип координаты int соответствует аргументу, являющемуся индексом в массиве byte[]. Возвращаемый VarHandle обращается к байтам по индексу в ByteBuffer, формируя байты для значения компонентного типа viewArrayClass в соответствии с заданным порядком байтов. Поддерживаемые компонентные типы (типы переменных) — это short, char, int, long, float и double.
Обращение к любому режиму доступа, кроме чтения, вызовет исключение ReadOnlyBufferException, если ByteBuffer доступно только для чтения.
Обращение к байтам по заданному индексу приведет к исключению IndexOutOfBoundsException, если индекс меньше 0 или больше предела ByteBuffer минус размер (в байтах) T.
Обращение к байтам по индексу может быть выровнено или не выровнено для T относительно базового адреса памяти, 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- если у получившегося обработчика метода будет слишком много параметров
invoker
public static MethodHandle invoker(MethodType type)
invoke. Получившийся обработчик будет иметь тип, точно соответствующий желаемому типу, за исключением дополнительного ведущего аргумента типа MethodHandle. Перед вызовом целевого обработчика, если целевой обработчик отличается от ожидаемого типа, обработчик применит необходимые преобразования ссылок и преобразует, развернёт или расширит примитивные значения, как если бы использовалась asType. Аналогично, значение возврата будет преобразовано при необходимости. Если целевой обработчик является обработчиком метода с переменным количеством аргументов, будет выполнено требуемое преобразование арности, также как при использовании asType.
Этот метод эквивалентен следующему коду (хотя он может быть более эффективным): publicLookup().findVirtual(MethodHandle.class, "invoke", type)
Обсуждение: Общий тип метода — это тип, который упоминает только Object аргументы и значения возврата. Обработчик для такого типа может вызывать любой обработчик метода с такой же арностью, как у общего типа.
(Примечание: метод-обработчик недоступен через API основного отражения. Попытка вызвать java.lang.reflect.Method.invoke на объявленном invokeExact или invoke методе вызовет UnsupportedOperationException.)
Этот метод не генерирует отражательные или защитные исключения.
- Параметры:
-
type- желаемый тип целевого обработчика - Возвращает:
- обработчик метода, подходящий для вызова любого преобразуемого в заданный тип обработчика метода
- Исключения:
-
IllegalArgumentException- если у получившегося обработчика метода будет слишком много параметров
varHandleExactInvoker
public static MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode, MethodType type)
VarHandle.- Параметры:
-
accessMode- режим доступа VarHandle -
type- желаемый тип целевого обработчика - Возвращает:
- обработчик метода, подходящий для вызова метода режима доступа любого VarHandle, тип режима доступа которого соответствует заданному типу.
- Since:
- 9
varHandleInvoker
public static MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type)
VarHandle. Перед вызовом целевого обработчика, если тип режима доступа отличается от желаемого заданного типа, обработчик применит необходимые преобразования ссылок и преобразует, развернёт или расширит примитивные значения, как если бы использовалась asType. Аналогично, значение возврата будет преобразовано при необходимости.
Этот метод эквивалентен следующему коду (хотя он может быть более эффективным): publicLookup().findVirtual(VarHandle.class, accessMode.name(), type)
- Параметры:
-
accessMode- режим доступа VarHandle -
type- желаемый тип целевого обработчика - Возвращает:
- обработчик метода, подходящий для вызова метода режима доступа любого VarHandle, тип режима доступа которого преобразуем к заданному типу.
- Since:
- 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 во время выполнения, вводится значение нуля.
- Parameters:
-
target- обработчик метода, который вызывается после повторной типизации аргументов -
newType- ожидаемый тип нового обработчика метода - Returns:
- обработчик метода, который делегирует целевому обработчику после выполнения необходимых преобразований аргументов и организует необходимые преобразования возвращаемого значения
- Throws:
-
NullPointerException- если любой из аргументов равен null -
WrongMethodTypeException- если преобразование невозможно - See Also:
permuteArguments
public static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder)
Перестановка определяется заданным массивом. Вызовите #I для количества входных параметров (значение newType.parameterCount()), и вызовите #O для количества выходных параметров (значение target.type().parameterCount()). Тогда длина массива перестановки должна быть #O, а каждый элемент должен быть целым числом, неотрицательным и меньше #I. Для каждого N меньше #O, N-й выходной аргумент будет взят из I-го входного аргумента, где I есть reorder[N].
Преобразования аргументов или возвращаемых значений не применяются. Тип каждого входного аргумента, определяемый newType, должен быть идентичен типу соответствующего выходного параметра или параметров в целевом обработчике метода. Тип возвращаемого значения newType должен быть идентичен типу возвращаемого значения исходного целевого обработчика.
Массив перестановки не обязательно должен задавать фактическую перестановку. Входной аргумент будет продублирован, если его индекс встречается в массиве более одного раза, а входной аргумент будет пропущен, если его индекс не встречается в массиве. Как и в случае с dropArguments, входные аргументы, которые не указаны в массиве перестановки, могут иметь любой тип, определяемый только newType.
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodType intfn1 = methodType(int.class, int.class);
MethodType intfn2 = methodType(int.class, int.class, int.class);
MethodHandle sub = ... (int x, int y) -> (x-y) ...;
assert(sub.type().equals(intfn2));
MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
assert((int)rsub.invokeExact(1, 100) == 99);
MethodHandle add = ... (int x, int y) -> (x+y) ...;
assert(add.type().equals(intfn2));
MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
assert(twice.type().equals(intfn1));
assert((int)twice.invokeExact(21) == 42);
Примечание: Результирующий адаптер никогда не является обработчиком метода с переменным числом аргументов, даже если исходный целевой обработчик метода был таковым.
- Parameters:
-
target- обработчик метода, который вызывается после перестановки аргументов -
newType- ожидаемый тип нового обработчика метода -
reorder- массив индексов, который управляет перестановкой - Returns:
- обработчик метода, который делегирует целевому обработчику после удаления неиспользуемых аргументов и перемещения и/или дублирования других аргументов
- Throws:
-
NullPointerException- если какой-либо аргумент равен null -
IllegalArgumentException- если длина массива индексов не равна арности целевого обработчика или если какой-либо элемент массива индексов не является допустимым индексом для параметраnewType, или если два соответствующих типа параметров вtarget.type()иnewTypeне идентичны
constant
public static MethodHandle constant(Class<?> type, Object value)
Перед возвратом обработчика метода переданное значение преобразуется к запрошенному типу. Если запрошенный тип примитивный, предпринимаются попытки расширяющих преобразований примитивных типов, иначе предпринимаются попытки преобразований ссылок.
Возвращаемый обработчик метода эквивалентен identity(type).bindTo(value).
- Parameters:
-
type- тип возвращаемого значения желаемого обработчика метода -
value- значение, которое нужно вернуть - Returns:
- обработчик метода заданного типа без аргументов, который всегда возвращает данное значение
- Throws:
-
NullPointerException- если аргументtypeравен null -
ClassCastException- если значение нельзя преобразовать в требуемый тип возвращаемого значения -
IllegalArgumentException- если заданный тип являетсяvoid.class
identity
public static MethodHandle identity(Class<?> type)
- Parameters:
-
type- тип единственного параметра и возвращаемого значения желаемого обработчика метода - Returns:
- унарный обработчик метода, который принимает и возвращает заданный тип
- Throws:
-
NullPointerException- если аргумент равен null -
IllegalArgumentException- если заданный тип являетсяvoid.class
zero
public static MethodHandle zero(Class<?> type)
Возвращаемый обработчик метода эквивалентен empty(methodType(type)). Он также эквивалентен explicitCastArguments(constant(Object.class, null), methodType(type)), так как explicitCastArguments преобразует null в значения по умолчанию.
- Parameters:
-
type- ожидаемый тип возвращаемого значения желаемого обработчика метода - Returns:
- обработчик константного метода, не принимающий аргументов и возвращающий значение по умолчанию заданного типа (или void, если тип void)
- Throws:
-
NullPointerException- если аргумент равен null - Since:
- 9
- See Also:
empty
public static MethodHandle empty(MethodType type)
Возвращаемый обработчик метода эквивалентен dropArguments(zero(type.returnType()), 0, type.parameterList()).
- API Note:
- При заданном предикате и целевом объекте можно создать полезную конструкцию «если-то» как
guardWithTest(pred, target, empty(target.type()). - Parameters:
-
type- тип желаемого обработчика метода - Returns:
- обработчик константного метода заданного типа, который возвращает значение по умолчанию для заданного типа возвращаемого значения
- Throws:
-
NullPointerException- если аргумент равен null - Since:
- 9
- See Also:
insertArguments
public static MethodHandle insertArguments(MethodHandle target, int pos, Object... values)
Тип нового обработчика метода будет исключать типы связанных параметров из исходного типа целевого объекта, так как новому обработчику метода больше не понадобятся эти аргументы, предоставляемые его вызывающими сторонами.
Каждый заданный объект аргумента должен соответствовать соответствующему типу связанного параметра. Если тип связанного параметра является примитивным, объект аргумента должен быть оберткой, и он будет распакован для получения примитивного значения.
Аргумент pos выбирает, какие параметры должны быть связаны. Он может изменяться от нуля до N-L (включительно), где N — арность целевого обработчика метода, а L — длина массива значений.
Примечание: Результирующий адаптер никогда не является обработчиком метода с переменным числом аргументов, даже если исходный целевой обработчик метода был таковым.
- Parameters:
-
target- обработчик метода, который нужно вызвать после вставки аргумента -
pos- место вставки аргумента (ноль для первого) -
values- серия аргументов для вставки - Returns:
- обработчик метода, который вставляет дополнительный аргумент перед вызовом исходного обработчика метода
- Throws:
-
NullPointerException- если целевой объект или массивvaluesравен null -
IllegalArgumentException- еслиposменьше0или большеN - L, гдеN— арность целевого обработчика метода, аL— длина массива значений. -
ClassCastException- если аргумент не соответствует соответствующему типу связанного параметра. - See Also:
dropArguments
public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes)
Аргумент pos может изменяться от нуля до N, где N — арность целевого объекта. Если pos равен нулю, фиктивные аргументы будут предшествовать реальным аргументам целевого объекта; если pos равен N, они будут следовать за ними.
Пример:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
assertEquals(bigType, d0.type());
assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
Этот метод также эквивалентен следующему коду:
dropArguments(target, pos, valueTypes.toArray(new Class[0]))
- Parameters:
-
target- обработчик метода, который нужно вызвать после отбрасывания аргументов -
pos- позиция первого аргумента для отбрасывания (ноль для левого) -
valueTypes- тип(ы) аргумента(ов) для отбрасывания - Returns:
- обработчик метода, который отбрасывает аргументы указанных типов перед вызовом исходного обработчика метода
- Throws:
-
NullPointerException- если целевой объект равен null, или если списокvalueTypesили любой его элемент равен null -
IllegalArgumentException- если любой элемент изvalueTypesравенvoid.class, или еслиposотрицательный или больше арности целевого объекта, или если у нового обработчика метода будет слишком много параметров
dropArguments
public static MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes)
Аргумент pos может изменяться от нуля до N, где N — арность целевого объекта. Если pos равен нулю, фиктивные аргументы будут предшествовать реальным аргументам целевого объекта; если pos равен N, они будут следовать за ними.
- API Note:
-
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)) - Parameters:
-
target- обработчик метода, который нужно вызвать после отбрасывания аргументов -
pos- позиция первого аргумента для отбрасывания (ноль для левого) -
valueTypes- тип(ы) аргумента(ов) для отбрасывания - Returns:
- обработчик метода, который отбрасывает аргументы указанных типов перед вызовом исходного обработчика метода
- Throws:
-
NullPointerException- если целевой объект равен null, или если массивvalueTypesили любой его элемент равен null -
IllegalArgumentException- если любой элемент изvalueTypesравенvoid.class, или еслиposотрицательный или больше арности целевого объекта, или если у нового обработчика метода будет слишком много параметров
dropArgumentsToMatch
public static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos)
target должны быть подсписком списка типов newTypes в начальной позиции pos. Результирующий обработчик будет иметь список типов параметров целевого обработчика, с любыми несовпадающими типами параметров (до или после соответствующего подсписка) в соответствующих позициях оригинальных параметров целевого объекта, как если бы это было сделано с помощью dropArguments(MethodHandle, int, Class[]). Результирующий обработчик будет иметь тот же тип возвращаемого значения, что и целевой обработчик.
В более формальном представлении, предположим эти два списка типов:
- Целевой обработчик имеет список типов параметров
S..., M..., с количеством типов вS, указаннымskip. ТипыM- это те, которые должны соответствовать части данного списка типовnewTypes. - Список
newTypesсодержит типыP..., M..., A..., с количеством типов вP, указаннымpos. ТипыM- это те типы, которые должны соответствовать типамMв списке типов параметров целевого обработчика. Типы вA- дополнительные типы, обнаруженные после соответствующего подсписка.
dropArgumentsToMatch будет иметь список типов параметров S..., P..., M..., A..., с типами P и A, вставленными как если бы это было сделано с помощью dropArguments(MethodHandle, int, Class[]).- API Note:
- Два обработчика методов, списки аргументов которых "эффективно идентичны" (т.е. идентичны в общем префиксе), могут быть взаимно преобразованы в общий тип с помощью двух вызовов
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")); - Parameters:
-
target- обработчик метода для адаптации -
skip- количество параметров целевого объекта, которые нужно проигнорировать (они останутся неизменными) -
newTypes- список типов, с которыми необходимо сопоставить список типов параметровtarget -
pos- место в спискеnewTypes, где должны находиться параметры целевого объекта, которые не были пропущены - Returns:
- возможно адаптированный обработчик метода
- Throws:
-
NullPointerException- если любой из аргументов равен null -
IllegalArgumentException- если любой элемент изnewTypesравенvoid.class, или еслиskipотрицательный или больше арности целевого объекта, или еслиposотрицательный или больше размера списка newTypes, или еслиnewTypesне содержит типы параметров целевого объекта, которые не были пропущены, в позицииpos. - Since:
- 9
dropReturn
public static MethodHandle dropReturn(MethodHandle target)
void.- Parameters:
-
target- обработчик метода для адаптации - Returns:
- возможно адаптированный обработчик метода
- Throws:
-
NullPointerException- еслиtargetравен null - Since:
- 16
filterArguments
public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters)
Предварительная обработка выполняется одним или несколькими обработчиками методов, указанными в элементах массива filters. Первый элемент массива фильтров соответствует аргументу pos целевого обработчика, и так далее последовательно. Функции фильтра вызываются слева направо.
Нулевые аргументы в массиве обрабатываются как тождественные функции, а соответствующие аргументы остаются неизменными. (Если в массиве нет ненулевых элементов, возвращается исходный целевой обработчик.) Каждый фильтр применяется к соответствующему аргументу адаптера.
Если фильтр F применяется к аргументу под номером N целевого обработчика, то F должен быть обработчиком метода, принимающим ровно один аргумент. Тип единственного аргумента F заменяет соответствующий тип аргумента целевого обработчика в результирующем адаптированном обработчике методов. Тип возвращаемого значения F должен быть идентичен соответствующему параметру типа целевого обработчика.
Ошибка возникает, если есть элементы массива filters (нулевые или нет), которые не соответствуют позициям аргументов в целевом обработчике.
Пример:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
MethodHandle upcase = lookup().findVirtual(String.class,
"toUpperCase", methodType(String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle f0 = filterArguments(cat, 0, upcase);
assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
MethodHandle f1 = filterArguments(cat, 1, upcase);
assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
Вот псевдокод для результирующего адаптера. В коде T обозначает тип возвращаемого значения как для target, так и для результирующего адаптера. P/p и B/b представляют типы и значения параметров и аргументов, которые предшествуют и следуют за позицией фильтра pos, соответственно. A[i]/a[i] обозначают типы и значения отфильтрованных параметров и аргументов; они также представляют типы возвращаемых значений обработчиков filter[i]. Последние принимают аргументы v[i] типа V[i], которые также появляются в сигнатуре результирующего адаптера.
T target(P... p, A[i]... a[i], B... b);
A[i] filter[i](V[i]);
T adapter(P... p, V[i]... v[i], B... b) {
return target(p..., filter[i](v[i])..., b...);
}
Примечание: Результирующий адаптер никогда не является обработчиком методов с переменным числом аргументов, даже если исходный целевой обработчик методов был таким.
- Параметры:
-
target- обработчик методов, который вызывается после фильтрации аргументов -
pos- позиция первого аргумента для фильтрации -
filters- обработчики методов, вызываемые сначала для отфильтрованных аргументов - Возвращает:
- обработчик методов, включающий указанную логику фильтрации аргументов
- Исключения:
-
NullPointerException- если целевой обработчик методов равен null или если массивfiltersравен null -
IllegalArgumentException- если ненулевой элемент массиваfiltersне соответствует соответствующему типу аргумента целевого обработчика, как описано выше, или еслиpos+filters.lengthбольше, чемtarget.type().parameterCount(), или если тип результирующего обработчика методов будет иметь слишком много параметров
collectArguments
public static MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter)
Если фильтр возвращает значение, целевой обработчик должен принять это значение как аргумент в позиции pos, предшествующие и/или последующие аргументы, не переданные фильтру. Если фильтр возвращает пустоту, целевой обработчик должен принять все аргументы, не переданные фильтру. Аргументы не переупорядочиваются, и возвращаемое фильтром значение заменяет (по порядку) всю подпоследовательность аргументов, изначально переданных адаптеру.
Типы аргументов (если таковые имеются) фильтра заменяют ноль или один тип аргумента целевого обработчика, в позиции pos, в результирующем адаптированном обработчике методов. Тип возвращаемого значения фильтра (если таковой имеется) должен быть идентичен типу аргумента целевого обработчика в позиции pos, и этот аргумент целевого обработчика предоставляется возвращаемым значением фильтра.
Во всех случаях, pos должно быть больше или равно нулю, а pos также должно быть меньше или равно арности целевого обработчика.
Пример:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle deepToString = publicLookup()
.findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
assertEquals("[strange]", (String) ts1.invokeExact("strange"));
MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
assertEquals("[top, [up, down], strange]",
(String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
assertEquals("[top, [up, down], [strange]]",
(String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
assertEquals("[top, [[up, down, strange], charm], bottom]",
(String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
Вот псевдокод для результирующего адаптера. В коде T представляет тип возвращаемого значения как для target, так и для результирующего адаптера. V/v обозначают тип возвращаемого значения и значение filter, которые также находятся в сигнатуре и аргументах target, соответственно, если только V не равно void. A/a и C/c представляют типы параметров и значения, предшествующие и последующие позиции сбора pos в сигнатуре target. Они также появляются в сигнатуре и аргументах результирующего адаптера, где они окружают B/b, которые представляют типы параметров и аргументы для filter (если таковые имеются).
T target(A...,V,C...);
V filter(B...);
T adapter(A... a,B... b,C... c) {
V v = filter(b...);
return target(a...,v,c...);
}
// and if the filter has no arguments:
T target2(A...,V,C...);
V filter2();
T adapter2(A... a,C... c) {
V v = filter2();
return target2(a...,v,c...);
}
// and if the filter has a void return:
T target3(A...,C...);
void filter3(B...);
T adapter3(A... a,B... b,C... c) {
filter3(b...);
return target3(a...,c...);
}
Адаптер сбора collectArguments(mh, 0, coll) эквивалентен адаптеру, который сначала "складывает" затронутые аргументы, а затем удаляет их, в отдельных шагах следующим образом:
mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
mh = MethodHandles.foldArguments(mh, coll); //step 1
coll, то collectArguments(mh, 0, coll) эквивалентно filterReturnValue(coll, mh). Если обработчик методов фильтра coll потребляет один аргумент и генерирует непустое возвращаемое значение, то collectArguments(mh, N, coll) эквивалентно filterArguments(mh, N, coll). Другие эквивалентности возможны, но потребуют перестановки аргументов. Примечание: Результирующий адаптер никогда не является обработчиком методов с переменным числом аргументов, даже если исходный целевой обработчик методов был таким.
- Параметры:
-
target- обработчик методов, который вызывается после фильтрации подпоследовательности аргументов -
pos- позиция первого аргумента адаптера, передаваемого фильтру, и/или аргумента целевого обработчика, который получает результат фильтра -
filter- обработчик методов, вызываемый для подпоследовательности аргументов - Возвращает:
- обработчик методов, включающий указанную логику фильтрации подпоследовательности аргументов
- Исключения:
-
NullPointerException- если любой из аргументов равен null -
IllegalArgumentException- если тип возвращаемого значенияfilterне пустой и не совпадает с аргументомposцелевого обработчика, или еслиposне находится в диапазоне от 0 до арности целевого обработчика включительно, или если тип результирующего обработчика методов будет иметь слишком много параметров - См. также:
filterReturnValue
public static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter)
Если целевой обработчик возвращает значение, фильтр должен принять это значение в качестве единственного аргумента. Если целевой обработчик возвращает пустоту, фильтр не должен принимать аргументы.
Тип возвращаемого значения фильтра заменяет тип возвращаемого значения целевого обработчика в результирующем адаптированном обработчике методов. Тип аргумента фильтра (если таковой имеется) должен быть идентичен типу возвращаемого значения целевого обработчика.
Пример:
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 типы параметров целевого обработчика должны точно совпадать с типами параметров комбинирующего обработчика.
Если у комбинирующего обработчика пустое возвращаемое значение, результат не будет вставлен, и первые N типы параметров целевого обработчика должны точно совпадать с типами параметров комбинирующего обработчика.
Результирующий адаптер имеет тот же тип, что и целевой, за исключением того, что первый тип параметра опускается, если он соответствует результату комбинирующего обработчика.
(Обратите внимание, что dropArguments можно использовать для удаления любых аргументов, которые не требуются ни комбинирующим, ни целевым обработчикам. Если некоторые входные аргументы предназначены только для комбинирующего обработчика, рассмотрите использование asCollector, поскольку эти аргументы не должны быть активны в стеке при вызове целевого обработчика.)
Пример:
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
...
MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
"println", methodType(void.class, String.class))
.bindTo(System.out);
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
MethodHandle catTrace = foldArguments(cat, trace);
// also prints "boo":
assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
Вот псевдокод для результирующего адаптера. В коде T представляет тип возвращаемого значения target и результирующего адаптера. V/v представляют тип и значение параметра и аргумента target, предшествующего позиции сгиба; V также является типом возвращаемого значения combiner. A/a обозначают типы и значения N параметров и аргументов в позиции сгиба. B/b представляют типы и значения target параметров и аргументов, которые следуют за сложенными параметрами и аргументами.
// there are N arguments in A...
T target(V, A[N]..., B...);
V combiner(A...);
T adapter(A... a, B... b) {
V v = combiner(a...);
return target(v, a..., b...);
}
// and if the combiner has a void return:
T target2(A[N]..., B...);
void combiner2(A...);
T adapter2(A... a, B... b) {
combiner2(a...);
return target2(a..., b...);
}
Примечание: результирующий адаптер никогда не является обработчиком методов с переменным числом аргументов, даже если исходный целевой обработчик методов был таким.
- Параметры:
-
target- обработчик методов, вызываемый после комбинирования аргументов -
combiner- обработчик методов, вызываемый первоначально на входных аргументах - Возвращает:
- обработчик методов, включающий указанную логику сгиба аргументов
- Исключение:
-
NullPointerException- если любой из аргументов равен null -
IllegalArgumentException- если тип возвратаcombinerне пустой и не совпадает с первым типом аргумента целевого обработчика, или если начальные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. - C момента:
- 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...) и (a...). Они становятся параметрами полученного обработчика цикла, которые необходимо предоставить при выполнении цикла. (Поскольку функции init не принимают переменные итерации v, любой параметр функции init автоматически является параметром цикла a.) Как и переменные итерации, функции клаузы могут, но не обязаны принимать параметры цикла. Эти параметры цикла действуют как инвариантные значения цикла, видимые во всём цикле.
Параметры, видимые везде: Каждая функция клаузы, не являющаяся функцией init, имеет право наблюдать за состоянием всего цикла, потому что ей может быть передан полный список (v... a...) текущих значений переменных итерации и входящих параметров цикла. Функции init могут наблюдать начальное состояние до цикла в форме (a...). Большинству функций клаузы не потребуется вся эта информация, но они формально будут связаны с ней так, как если бы с помощью dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>). Более конкретно, мы будем использовать обозначение (V*) для выражения произвольного префикса полного последовательности (V...) (и аналогично для (v*), (A*), (a*)). В этом обозначении общий вид списка параметров функции init — (A*), а общий вид списка параметров функции, не являющейся функцией init, — (V*) или (V... A*).
Проверка структуры клаузы: Для набора клауз выполняется ряд проверок и корректировок для соединения всех частей цикла. Подробное описание этих этапов приведено ниже. В этих этапах каждое вхождение слова "должен" соответствует месту, где IllegalArgumentException будет выброшено, если требуемое ограничение не выполняется входными данными в комбинатор цикла.
Эффективно идентичные последовательности: Список параметров A определяется как эффективно идентичный другому списку параметров B, если A и B идентичны, или если A короче и идентичен правильному префиксу B. При упоминании неупорядоченного набора списков параметров, мы говорим, что набор "эффективно идентичен" в целом, если набор содержит самый длинный список, и все члены набора эффективны идентичны этому самому длинному списку. Например, любой набор последовательностей типов в форме (V*) эффективно идентичен, и то же самое верно, если добавлены дополнительные последовательности в форме (V... A*).
Шаг 0: Определение структуры клаузы.
- Массив клаузы (типа
MethodHandle[][]) не должен быть пустым и содержать по крайней мере один элемент. - Массив клаузы не может содержать
nullили подмассивы длиной более четырёх элементов. - Клаузы, короче четырёх элементов, обрабатываются так, как если бы они были дополнены
nullэлементами до длины четыре. Дополнение происходит путём добавления элементов в массив. - Клаузы с все
nullэлементами игнорируются. - Каждая клауза рассматривается как четвёрка функций, называемых "init", "step", "pred" и "fini".
Шаг 1А: Определение типов переменных итерации (V...).
- Тип переменной итерации для каждой клаузы определяется с использованием типов возвращаемых значений функций init и step.
- Если обе функции опущены, для соответствующей клаузы нет переменной итерации (
voidиспользуется как тип для указания этого). Если одна из них опущена, тип возврата другой определяет тип переменной итерации клаузы. Если обе заданы, общий тип возврата (они должны быть одинаковыми) определяет тип переменной итерации клаузы. - Сформировать список типов возврата (в порядке клаузы), исключая все вхождения
void. - Этот список типов называется "типами переменных итерации" (
(V...)).
Шаг 1В: Определение параметров цикла (A...).
- Просмотреть и собрать списки параметров функций init (они имеют вид
(A*)). - Просмотреть и собрать суффиксы списков параметров step, pred и fini после удаления типов переменных итерации. (Они должны иметь вид
(V... A*); собираются только части(A*)). - Не собирать суффиксы из списков параметров step, pred и fini, которые не начинаются со всех типов переменных итерации. (Эти типы будут проверены на шаге 2 вместе со всеми типами функций клаузы.)
- Опущенные функции клаузы игнорируются. (Эквивалентно, считается, что у них есть пустые списки параметров.)
- Все собранные списки параметров должны быть эффективно идентичны.
- Самый длинный список параметров (который обязательно уникален) называется "внешним списком параметров" (
(A...)). - Если такого списка параметров нет, внешний список параметров считается пустой последовательностью.
- Объединённый список, состоящий из типов переменных итерации и типов внешних параметров, называется "внутренним списком параметров".
Шаг 1С: Определение типа возврата цикла.
- Просмотреть типы возврата функций fini, игнорируя опущенные функции fini.
- Если функций fini нет, тип возврата цикла —
void. - В противном случае общий тип возврата
Rфункций fini (их типы возврата должны быть одинаковыми) определяет тип возврата цикла.
Шаг 1D: Проверка других типов.
- Должна быть как минимум одна неотменённая функция pred.
- У каждой неотменённой функции pred должен быть
booleanтип возврата.
Шаг 2: Определение списков параметров.
- Список параметров для результирующего обработчика цикла будет внешним списком параметров
(A...). - Список параметров для функций init будет скорректирован до внешнего списка параметров. (Обратите внимание, что их списки параметров уже эффективно идентичны этому списку.)
- Список параметров каждой неотменённой функции, не являющейся функцией init (step, pred и fini), должен быть эффективно идентичен внутреннему списку параметров
(V... A...).
Шаг 3: Заполнение опущенных функций.
- Если функция init опущена, используется значение по умолчанию для типа переменной итерации клаузы.
- Если функция step опущена, используется функция идентичности типа переменной итерации клаузы; вставляются параметры отброшенных аргументов перед параметром функции идентичности для не-
voidпеременных итерации предыдущих клаузов. (Это превратит переменную цикла в локальную инварианту цикла.) - Если функция pred опущена, используется постоянная
trueфункция. (Это позволит циклу продолжаться с точки зрения этой клаузы. Обратите внимание, что в таких случаях соответствующая функция fini недоступна.) - Если функция fini опущена, используется значение по умолчанию для типа возврата цикла.
Шаг 4: Заполнение отсутствующих типов параметров.
- На этом этапе каждый список параметров функции init эффективно идентичен внешнему списку параметров
(A...), но некоторые списки могут быть короче. Для каждой функции init с коротким списком параметров дополните конец списка. - На этом этапе каждый список параметров функции, не являющейся функцией init, эффективно идентичен внутреннему списку параметров
(V... A...), но некоторые списки могут быть короче. Для каждой функции, не являющейся функцией init, с коротким списком параметров дополните конец списка. - Списки аргументов дополняются путём удаления неиспользуемых последующих аргументов.
Заключительные замечания.
- После этих шагов все предложения были скорректированы путём предоставления пропущенных функций и аргументов.
- Все функции инициализации имеют общий список типов параметров
(A...), который также будет иметь конечная обработка цикла. - Все функции завершения имеют общий тип возвращаемого значения
R, который также будет иметь конечная обработка цикла. - Все функции, не являющиеся функциями инициализации, имеют общий список типов параметров
(V... A...), содержащий (не-void) переменные итерацииV, за которыми следуют параметры цикла. - Каждая пара функций инициализации и шага согласуется в своём типе возвращаемого значения
V. - Каждая функция, не являющаяся функцией инициализации, сможет наблюдать текущие значения
(v...)всех переменных итерации. - Каждая функция сможет наблюдать входные значения
(a...)всех параметров цикла.
Пример. Вследствие шага 1А выше, комбинатор loop имеет следующее свойство:
- Учитывая
NпредложенияCn = {null, Sn, Pn}сn = 1..N. - Предполагается, что обработчики предикатов
Pnлибо являютсяnull, либо не имеют параметров. (Только одинPnдолжен быть не-null.) - Предполагается, что обработчики шага
Snимеют сигнатуры(B1..BX)Rnдля некоторой константыX>=N. - Предполагается, что
Q— это количество типов, не являющихся void,Rn, а(V1...VQ)— последовательность этих типов. - Должно выполняться условие
Vn == Bnдляn = 1..min(X,Q). - Типы параметров
Vnбудут интерпретироваться как локальные элементы состояния цикла(V...). - Любые оставшиеся типы
BQ+1..BX(еслиQ<X) будут определять типы параметров результирующей обработки цикла(A...).
(A...) были получены из функций шага, что естественно, если основная вычислительная работа цикла происходит в шагах. Для некоторых циклов основная вычислительная нагрузка может приходиться на функции предикатов, и поэтому функции предикатов могут нуждаться в принятии значений параметров цикла. Для циклов со сложной логикой выхода функции завершения могут нуждаться в принятии параметров цикла, и то же самое относится к циклам со сложной логикой входа, где функции инициализации потребуют дополнительных параметров. По этим причинам правила определения этих параметров максимально симметричны по всем частям предложений. В общем случае параметры цикла функционируют как общие неизменяемые значения в рамках всего цикла, а переменные итерации — как общие изменяемые значения, или (если нет функции шага) как временные локальные неизменяемые значения цикла. Выполнение цикла.
- При вызове цикла входные значения цикла сохраняются в локальных переменных, которые передаются каждой функции предложения. Эти локальные переменные являются неизменяемыми в цикле.
- Каждая функция инициализации выполняется в порядке предложений (передавая внешние аргументы
(a...)), и значения, не являющиесяvoid, сохраняются (как переменные итерации(v...)) в локальные переменные. Эти локальные переменные будут изменяться в цикле (если их шаги ведут себя как тождественные функции, как указано выше). - Все выполнения функций (кроме функций инициализации) будут получать внутренний список параметров, состоящий из значений переменных итерации, не являющихся
void(в порядке предложений), а затем входных данных цикла(a...)(в порядке аргументов). - Затем функции шага и предиката выполняются в порядке предложений (шаг перед предикатом) до тех пор, пока функция предиката не вернёт
false. - Результат, не являющийся
void, из вызова функции шага используется для обновления соответствующего значения в последовательности(v...)переменных цикла. Обновлённое значение немедленно доступно для всех последующих вызовов функций. - Если функция предиката возвращает
false, соответствующая функция завершения вызывается, а полученное значение (типаR) возвращается из цикла в целом. - Если все функции предиката всегда возвращают true, ни одна функция завершения никогда не вызывается, и цикл не может завершиться, кроме как путём выброса исключения.
Советы по использованию.
- Хотя каждая функция шага получит текущие значения всех переменных цикла, иногда функции шага требуется только наблюдать текущее значение собственной переменной. В этом случае функция шага может потребовать явно отбросить все предыдущие переменные цикла. Для этого потребуется указать их типы в выражении, подобном
dropArguments(step, 0, V0.class, ...). - Переменные цикла не обязательно должны изменяться; они могут быть неизменяемыми в цикле. Предложение может создать неизменяемую переменную цикла с помощью подходящей функции инициализации без функции шага, предиката или завершения. Это может быть полезно для «подключения» входного аргумента цикла к функции шага или предиката соседней переменной цикла.
- Если некоторые из функций предложения являются виртуальными методами для экземпляра, сам экземпляр удобно поместить в начальную неизменяемую переменную цикла, используя начальное предложение, подобное
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. - C момента:
- 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. - C момента:
- 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— обработчик, не возвращающийnull, который возвращает количество итераций, которые должен выполнить этот цикл. Тип результата обработчика должен бытьint. Смотрите выше указанные ограничения. -
init— необязательная инициализация, предоставляющая начальное значение переменной цикла. Может бытьnull, подразумевая значение инициализации по умолчанию. Смотрите выше указанные ограничения. -
body— тело цикла, которое не может бытьnull. Оно управляет параметрами цикла и типом результата в стандартном случае (см. выше для подробностей). Оно должно принимать свой собственный тип возврата (если не void) плюс параметрint(для счётчика) и может принимать любое количество дополнительных типов. Смотрите выше указанные ограничения. - Возвращает:
- обработчик метода, представляющий цикл.
- Исключения:
-
NullPointerException— если какой-либо изiterationsилиbodyобработчиков являетсяnull. -
IllegalArgumentException— если любой аргумент нарушает сформулированные выше правила. - С:
- 9
- См. также:
countedLoop
public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body)
Счётчик цикла i — это переменная итерации цикла типа int. Обработчики start и end определяют начальное (включительно) и конечное (исключительно) значения счётчика цикла. Счётчик цикла будет инициализирован значением int, полученным от оценки обработчика start, и доходить до значения, возвращаемого обработчиком end (исключая), с шагом 1.
Если обработчик body возвращает тип, отличный от void, то присутствует ведущая переменная итерации этого типа. Эта переменная инициализируется с помощью необязательного обработчика 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являетсяnull. -
IllegalArgumentException— если какой-либо аргумент нарушает сформулированные выше правила. - С:
- 9
- См. также:
iteratedLoop
public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body)
Iterator<T>. Это обертка для общих комбинаторов циклов.
Сам итератор определяется значением iterator обработчика. Каждое производимое им значение хранится в переменной цикла типа T.
Если body обработчик возвращает тип, отличный от void, V, то присутствует ведущая переменная цикла этого типа. Эта переменная инициализируется с помощью необязательного init обработчика или по умолчанию типа V, если этот обработчик отсутствует.
В каждом цикле переменные цикла передаются в вызов 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 или нулевые значения.)
Обработчики target и cleanup должны иметь одинаковые соответствующие типы аргументов и возвращаемых значений, за исключением того, что обработчик cleanup может опускать хвостовые аргументы. Также обработчик cleanup должен иметь один или два дополнительных ведущих параметра:
- тип
Throwable, который будет содержать исключение, сгенерированное обработчикомtarget(если таковое имеется); и - параметр того же типа, что и тип возвращаемого значения обоих обработчиков
targetиcleanup, который будет содержать результат выполнения обработчикаtarget. Этот параметр отсутствует, еслиtargetвозвращаетvoid.
Псевдокод для результирующего адаптера выглядит следующим образом. В коде V представляет тип возвращаемого значения конструкции try/finally; A/a — типы и значения аргументов результирующего обработчика, потребляемые очисткой; и B/b — те же значения аргументов, отбрасываемые очисткой.
V target(A..., B...);
V cleanup(Throwable, V, A...);
V adapter(A... a, B... b) {
V result = (zero value for V);
Throwable throwable = null;
try {
result = target(a..., b...);
} catch (Throwable t) {
throwable = t;
throw t;
} finally {
result = cleanup(throwable, result, a...);
}
return result;
}
Обратите внимание, что сохранённые аргументы (a... в псевдокоде) не могут быть изменены во время выполнения целевого кода и передаются неизменными от вызывающей стороны к обработке, если она вызывается.
Целевой и обработчик очистки должны возвращать один и тот же тип, даже если обработчик очистки всегда генерирует исключение. Для создания такого генерирующего исключения обработчика очистки комбинируйте логику очистки с throwException, чтобы создать обработчик метода с нужным типом возвращаемого значения.
Обратите внимание, что tryFinally никогда не преобразует исключения в нормальные возвращаемые значения. В редких случаях, когда исключения необходимо преобразовать таким образом, сначала оберните цель с помощью catchException(MethodHandle, Class, MethodHandle), чтобы захватить выходящее исключение, а затем оберните с помощью tryFinally.
Рекомендуется, чтобы первый тип параметра cleanup объявлялся как Throwable, а не как узкий подтип. Это гарантирует, что cleanup всегда будет вызываться с любым исключением, которое target сгенерирует. Объявление более узкого типа может привести к генерации исключения ClassCastException обработчиком try-finally, если тип исключения, сгенерированного 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или если типы обработчика падения и всех обработчиков целевых методов не совпадают.
memorySegmentViewVarHandle
public static VarHandle memorySegmentViewVarHandle(ValueLayoutPREVIEW layout)
memorySegmentViewVarHandle является предварительным API платформы Java. Предоставленный макет определяет тип носителяPREVIEW, размер в байтахPREVIEW, выравнивание в байтахPREVIEW и порядок байтовPREVIEW, связанные с возвращаемым varHandle.
Список типов координат, связанных с возвращаемым varHandle, равен (MemorySegment, long), где тип координаты long соответствует смещению в байтах в указанный сегмент памяти. Таким образом, возвращаемый varHandle обращается к байтам по смещению в заданном сегменте памяти, собирая байты в значение типа varHandle или извлекая из него байты. Кроме того, операция доступа будет учитывать порядок следования байтов (endianness) и ограничения на выравнивание, выраженные в предоставленном макете.
В качестве примера рассмотрим макет памяти, представленный экземпляром GroupLayoutPREVIEW, созданным следующим образом:
GroupLayout seq = java.lang.foreign.MemoryLayout.structLayout(
MemoryLayout.paddingLayout(4),
ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
);
value можно создать varHandle для просмотра сегмента памяти следующим образом: VarHandle handle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); //(MemorySegment, long) -> int
handle = MethodHandles.insertCoordinates(handle, 1, 4); //(MemorySegment) -> int
- Примечание API:
- Возвращаемый varHandle имеет определённые ограничения режима доступа, общие для всех varHandle, относящихся к сегменту памяти. VarHandle для просмотра сегмента памяти связан с размером доступа
Sи ограничением на выравниваниеB(оба выражены в байтах). Мы говорим, что операция доступа к памяти полностью выровнена, если она выполняется по адресу памятиA, совместимому с обоих ограничениями на выравниваниеSиB. Если доступ полностью выровнен, то поддерживаются следующие режимы доступа, и гарантируется поддержка атомарного доступа:- режимы чтения/записи для всех
T, за исключением режимов доступаgetиsetдляlongиdoubleна 32-битных платформах. - атомарные режимы обновления для
int,long,float,doubleилиMemorySegmentPREVIEW. (Будущие основные версии платформы JDK могут поддерживать дополнительные типы для некоторых в настоящее время неподдерживаемых режимов доступа). - численные атомарные режимы обновления для
int,longиMemorySegmentPREVIEW. (Будущие основные версии платформы JDK могут поддерживать дополнительные числовые типы для некоторых в настоящее время неподдерживаемых режимов доступа). - битовые атомарные режимы обновления для
int,longиMemorySegmentPREVIEW. (Будущие основные версии платформы JDK могут поддерживать дополнительные числовые типы для некоторых в настоящее время неподдерживаемых режимов доступа).
Tявляетсяfloat,doubleилиMemorySegmentPREVIEW, то атомарные режимы обновления сравнивают значения, используя их битовое представление (см.Float.floatToRawIntBits(float),Double.doubleToRawLongBits(double)иMemorySegment.address()PREVIEW соответственно).В противном случае операция доступа к памяти частично выровнена, если она выполняется по адресу памяти
A, совместимому только с ограничением на выравниваниеB; в таких случаях доступ к чему-либо, кроме режимов доступаgetиset, приведёт к исключениюIllegalStateException. Если доступ частично выровнен, атомарный доступ гарантируется только относительно наибольшей степени двойки, которая делит НОД (НОК)AиS.Во всех остальных случаях мы говорим, что операция доступа к памяти не выровнена; в таких случаях выбрасывается исключение
IllegalStateException, независимо от используемого режима доступа.Наконец, если
TравноMemorySegment, все режимы записи выбрасываютIllegalArgumentException, если записываемое значение не является нативнымPREVIEW сегментом памяти. - режимы чтения/записи для всех
- Параметры:
-
layout- макет значения, для которого требуется получить обработчик доступа к памяти. - Возвращает:
- новый обработчик varHandle для просмотра сегмента памяти.
- Исключения:
-
NullPointerException- еслиlayoutравенnull. - С:
- 19
- См. также:
filterValue
public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget)
filterValue является предварительным API платформы Java. filterValue только при включенных предварительных функциях.При вызове, например, VarHandle.set(Object...) на результирующем varHandle, входное значение (типа T, где T - тип последнего параметра первой функции фильтрации) обрабатывается с помощью первой функции фильтрации, а затем передаётся целевому varHandle. Аналогично, при вызове, например, VarHandle.get(Object...) на результирующем varHandle, возвращаемое значение, полученное от целевого varHandle (типа T, где T - тип последнего параметра второй функции фильтрации), обрабатывается второй функцией фильтрации и возвращается вызывающей стороне. Более сложные типы режимов доступа, такие как VarHandle.AccessMode.COMPARE_AND_EXCHANGE, могут применять оба фильтра одновременно.
Для того, чтобы функции фильтров преобразования в/из упакованный тип были корректны, их типы должны иметь вид (A... , S) -> T и (A... , T) -> S соответственно, где T - тип целевого varHandle. В этом случае результирующий varHandle будет иметь тип S и будет содержать дополнительные координаты A... (которые будут добавлены к координатам целевого varHandle).
Если функции фильтров преобразования в/из упакованный тип выбрасывают какие-либо проверенные исключения при вызове, результирующий varHandle будет выбрасывать исключение IllegalStateException.
Результирующий varHandle будет иметь те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой varHandle.
- Параметры:
-
target- целевой varHandle -
filterToTarget- фильтр для преобразования некоторого типаSв типtarget -
filterFromTarget- фильтр для преобразования типаtargetв некоторый типS - Возвращает:
- адаптер varHandle, который принимает новый тип, выполняя предоставленные преобразования в/из упакованный тип.
- Исключения:
-
IllegalArgumentException- еслиfilterFromTargetиfilterToTargetнекорректны, то есть их типы отличаются от(A... , S) -> Tи(A... , T) -> Sсоответственно, гдеT- тип целевого varHandle, или если установлено, чтоfilterFromTargetилиfilterToTargetвыбрасывают какие-либо проверенные исключения. -
NullPointerException- если любой из аргументов являетсяnull. - С:
- 19
filterCoordinates
public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters)
filterCoordinates является предварительной API платформы Java. filterCoordinates только при включенных предварительных функциях. При вызове, например, 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. - С тех пор:
- 19
insertCoordinates
public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values)
insertCoordinates является предварительной API платформы Java. insertCoordinates только при включенных предварительных функциях. При вызове, например, 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. - С тех пор:
- 19
permuteCoordinates
public static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder)
permuteCoordinates является предварительной API платформы Java. permuteCoordinates только при включенных предварительных функциях. Перестановка задается заданным массивом. Пусть 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. - С тех пор:
- 19
collectCoordinates
public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter)
collectCoordinates — это предварительный API платформы Java. collectCoordinates только при включенных предварительных функциях. Если R — тип возвращаемого значения фильтра (который не может быть void), целевой обработчик переменной должен принимать значение типа R в качестве координаты в позиции pos, предваряемое и/или сопровождаемое любыми координатами, не переданными фильтру. Координаты не переупорядочиваются, и возвращаемый фильтром результат заменяет (в порядке) всю подпоследовательность координат, изначально переданных адаптеру.
Типы аргументов (если таковые имеются) фильтра заменяют ноль или одну координаты типа целевого обработчика переменной в позиции pos в результирующем адаптированном обработчике переменной. Тип возвращаемого значения фильтра должен быть идентичен типу координаты целевого обработчика переменной в позиции pos, и эта координата целевого обработчика переменной поставляется значением, возвращаемым фильтром.
Если какой-либо из фильтров генерирует проверяемое исключение при вызове, результирующий обработчик переменной сгенерирует IllegalStateException.
Результирующий обработчик переменной будет иметь те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой обработчик переменной.
- Параметры:
-
target— обработчик переменной, который вызывается после фильтрации координат -
pos— позиция координаты для фильтрации -
filter— метод-обработчик фильтра - Возвращает:
- адаптер обработчика переменной, который фильтрует входящие значения координат перед вызовом целевого обработчика переменной
- Исключения:
-
IllegalArgumentException— если тип возвращаемого значенияfilterравен void, или он не совпадает с типом координатыposцелевого обработчика переменной, еслиposне находится в диапазоне от 0 до арности координат целевого обработчика переменной включительно, если у результирующего обработчика переменной будет слишком много координат или если определяется, чтоfilterгенерирует любые проверяемые исключения. -
NullPointerException— если любой из аргументов являетсяnull. - С:
- 19
dropCoordinates
public static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes)
dropCoordinates — это предварительный API платформы Java. dropCoordinates только при включенных предварительных функциях. Аргумент pos может находиться в диапазоне от нуля до N, где N — арность типов координат целевого обработчика переменной. Если pos равно нулю, фиктивные координаты будут предшествовать реальным аргументам цели; если pos равно N, они будут следовать за ними.
Результирующий обработчик переменной будет иметь те же режимы доступа (см. VarHandle.AccessMode) и гарантии атомарного доступа, что и целевой обработчик переменной.
- Параметры:
-
target— обработчик переменной, который вызывается после отбрасывания фиктивных координат -
pos— позиция первой отбрасываемой координаты (ноль для самой левой) -
valueTypes— тип(ы) отбрасываемой(ых) координаты(координат) - Возвращает:
- адаптер обработчика переменной, который отбрасывает некоторые фиктивные координаты перед вызовом целевого обработчика переменной
- Исключения:
-
IllegalArgumentException— еслиposне находится в диапазоне от 0 до арности координат целевого обработчика переменной включительно. -
NullPointerException— если любой из аргументов являетсяnullилиvalueTypesсодержитnull. - С:
- 19
© 1993, 2023, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/invoke/MethodHandles.html
memorySegmentViewVarHandleтолько при включенных предварительных функциях.