public class MethodHandles extends Object
Modifier and Type | Class and Description |
---|---|
static class |
MethodHandles.Lookup
查找对象是创建方法句柄的工厂,当创建需要访问检查时。
|
Modifier and Type | Method and Description |
---|---|
static MethodHandle |
arrayElementGetter(类<?> arrayClass)
产生方法句柄,提供对数组元素的读取访问。
|
static MethodHandle |
arrayElementSetter(类<?> arrayClass)
生成方法句柄,为数组的元素提供写访问权限。
|
static MethodHandle |
catchException(MethodHandle target, 类<? extends Throwable> exType, MethodHandle handler)
通过在异常处理程序中运行它来创建适应目标方法句柄的方法句柄。
|
static MethodHandle |
collectArguments(MethodHandle target, int pos, MethodHandle filter)
通过使用过滤器(另一种方法句柄)预处理其参数的子序列来适应目标方法句柄。
|
static MethodHandle |
constant(类<?> type, Object value)
生成请求的返回类型的方法句柄,每次调用时返回给定的常量值。
|
static MethodHandle |
dropArguments(MethodHandle target, int pos, 类<?>... valueTypes)
生成方法句柄,在调用其他
指定的方法句柄之前,将抛弃一些虚拟参数。
|
static MethodHandle |
dropArguments(MethodHandle target, int pos, List<类<?>> valueTypes)
生成方法句柄,在调用其他
指定的方法句柄之前,将抛弃一些虚拟参数。
|
static MethodHandle |
exactInvoker(MethodType type)
生成一个特殊的
调用方法句柄 ,可以用来调用给定类型的任何方法句柄,就像
invokeExact 一样 。
|
static MethodHandle |
explicitCastArguments(MethodHandle target, MethodType newType)
生成方法句柄,通过成对参数和返回类型转换将给定方法句柄的类型适配为新类型。
|
static MethodHandle |
filterArguments(MethodHandle target, int pos, MethodHandle... filters)
通过预处理其一个或多个参数来适应目标方法句柄,每个参数具有自己的一元过滤器函数,然后使用每个预处理的参数替换为相应过滤器函数的结果来调用目标。
|
static MethodHandle |
filterReturnValue(MethodHandle target, MethodHandle filter)
通过使用过滤器(另一种方法句柄)对其返回值(如果有的话)进行后处理来适应目标方法句柄。
|
static MethodHandle |
foldArguments(MethodHandle target, MethodHandle combiner)
通过预处理一些参数来适应目标方法句柄,然后调用具有预处理结果的目标,插入到原始的参数序列中。
|
static MethodHandle |
guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)
使用方法句柄来调整目标方法句柄,通过用测试保护它,一个布尔值方法句柄。
|
static MethodHandle |
identity(类<?> type)
生成方法句柄,在调用时返回其唯一参数。
|
static MethodHandle |
insertArguments(MethodHandle target, int pos, Object... values)
在方法句柄的调用之前提供一个具有一个或多个
绑定参数的目标方法句柄。
|
static MethodHandle |
invoker(MethodType type)
生成一个特殊的
调用方法句柄 ,可以用来调用与给定类型兼容的任何方法句柄,就像
invoke 一样 。
|
static MethodHandles.Lookup |
lookup()
返回 lookup object 全功能模拟来电的所有受支持字节码的行为。
|
static MethodHandle |
permuteArguments(MethodHandle target, MethodType newType, int... reorder)
生成方法句柄,通过重新排序参数,将方法句柄调整到新类型的调用顺序。
|
static MethodHandles.Lookup |
publicLookup()
返回 lookup object 这是可信的最低限度。
|
static <T extends Member> |
reflectAs(类<T> expected, MethodHandle target)
执行的一个未经检查的“裂纹”
direct method handle 。
|
static MethodHandle |
spreadInvoker(MethodType type, int leadingArgCount)
产生一个方法句柄,它将调用给定的
type 任何方法句柄,给定数量的尾随参数被一个
Object[] 数组替换。
|
static MethodHandle |
throwException(类<?> returnType, 类<? extends Throwable> exType)
产生一个方法句柄,它会抛出给定的
exType 。
|
public static MethodHandles.Lookup lookup()
lookup object
全功能模拟来电的所有受支持字节码的行为。
这些功能包括呼叫者的private access 。
查找对象上的工厂方法可以为调用者通过字节码(包括受保护和私有字段和方法)访问的任何成员创建direct method handles 。
该查找对象是可以被委托给可信代理的能力 。
不要将其存储在不受信任的代码可以访问的位置。
这种方法是调用者敏感的,这意味着它可能会向不同的呼叫者返回不同的值。
对于任何给定的呼叫者类别C
,此调用返回的查找对象具有与JVM提供的任何查找对象相同的能力,以便在同一个呼叫者类别C
中执行的invokedynamic instruction的引导方法。
public static MethodHandles.Lookup publicLookup()
lookup object
这是可信的最低限度。
它只能用于创建可公开访问的字段和方法的方法句柄。
作为纯粹的习惯问题,在lookup class此查询的对象将是Object
。
讨论:该查找类可以被改变为任何其他类C
使用形式的表达publicLookup().in(C.class)
。 由于所有类都具有公共名称的平等访问权限,所以这种更改将不会赋予新的访问权限。 公共查找对象总是受到security manager checks的约束 。 此外,它不能访问caller sensitive methods 。
public static <T extends Member> T reflectAs(类<T> expected, MethodHandle target)
Lookup.revealDirect
以获取其符号引用,然后调用MethodHandleInfo.reflectAs
来解析对成员的符号引用。
如果有一个安全管理员,它的checkPermission
方法被调用一个ReflectPermission("suppressAccessChecks")
权限。
T
- 所需类型的结果, Member
或子类型
target
- 一个直接的方法手柄来破解符号参考组件
expected
- 表示所需结果类型
T
的类对象
SecurityException
- 如果呼叫者没有权限呼叫
setAccessible
NullPointerException
- 如果任一参数是
null
IllegalArgumentException
- 如果目标不是一个直接的方法句柄
ClassCastException
- 如果该成员不是预期类型
public static MethodHandle arrayElementGetter(类<?> arrayClass) throws IllegalArgumentException
int
。
arrayClass
- 数组类型
NullPointerException
- 如果参数为空
IllegalArgumentException
- 如果arrayClass不是数组类型
public static MethodHandle arrayElementSetter(类<?> arrayClass) throws IllegalArgumentException
arrayClass
- 数组的类
NullPointerException
- 如果参数为空
IllegalArgumentException
- 如果arrayClass不是数组类型
public static MethodHandle spreadInvoker(MethodType type, int leadingArgCount)
type
任何方法句柄,给定数量的尾随参数被一个Object[]
数组替换。
生成的调用者将是一个方法句柄,其中包含以下参数:
MethodHandle
目标 leadingArgCount
计算) Object[]
数组 调用者将调用其目标,就像拨打invoke
一样, 标有type
。 也就是说,如果目标是给定的type
,它的行为就像invokeExact
; 否则它的行为就好像asType
用于将目标转换为所需的type
。
返回的调用者的类型不会是给定的type
,而是除了第一个leadingArgCount
之外的所有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
为空
IllegalArgumentException
- 如果
leadingArgCount
不在0到
type.parameterCount()
之间,或者如果结果方法句柄的类型将具有
too many parameters
public static MethodHandle exactInvoker(MethodType type)
invokeExact
一样 。
将得到的调用器将有一个类型,其正好等于所期望的类型,不同之处在于它将接受类型的附加参数领先MethodHandle
。
此方法相当于以下代码(尽管可能更有效): publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
讨论:当使用未知类型的变量方法句柄时,Invoker方法句柄可能很有用。 例如,为了模拟一个invokeExact
呼叫给一个变量的方法处理M
,提取其类型T
,查找该调用方法X
为T
,并调用调用方法,如X.invoke(T, A...)
。 (调用X.invokeExact
,因为T
类型是未知的)。如果需要扩展,收集或其他参数转换,则可以将它们应用于调用者X
一次, X
用于许多M
方法句柄值,只要它们与X的类型X
。
(注意:Invokeer方法不能通过Core Reflection API获得,尝试在声明的invokeExact
或invoke
方法上调用java.lang.reflect.Method.invoke将提升UnsupportedOperationException
))
此方法不会引发反思或安全异常。
type
- 所需的目标类型
IllegalArgumentException
- 如果结果方法句柄的类型将具有
too many parameters
public static MethodHandle invoker(MethodType type)
invoke
一样 。
将得到的调用器将有一个类型,其正好等于所期望的类型,不同之处在于它将接受类型的附加参数领先MethodHandle
。
在调用其目标之前,如果目标与预期类型不同,则调用者将根据需要应用引用转换,并使用box,unbox或者扩展原始值,如asType
所示 。 类似地,返回值将根据需要进行转换。 如果目标是variable arity method handle ,则将进行所需的转换,再次如asType
那样 。
此方法等同于以下代码(尽管可能更有效): publicLookup().findVirtual(MethodHandle.class, "invoke", type)
讨论:一个general method type是一个仅提到Object
参数和返回值。 这种类型的调用者能够调用与一般类型相同的任何方法句柄。
(注意:Invokeer方法不能通过Core Reflection API使用。尝试在声明的invokeExact
或invoke
方法上调用java.lang.reflect.Method.invoke将提升UnsupportedOperationException
)
此方法不会引发反思或安全异常。
type
- 所需的目标类型
IllegalArgumentException
- 如果结果方法句柄的类型将具有
too many parameters
public static MethodHandle explicitCastArguments(MethodHandle target, MethodType newType)
如果原始类型和新类型相等,则返回目标。
对于MethodHandle.asType
,允许使用相同的转换 ,如果转换失败,还会应用一些额外的转换。 给定类型T0 , T1 ,如果可能,应用以下转换之一,之前或代替asType完成的任何asType
:
(x & 1) != 0
。 target
- 在参数之后调用的方法句柄被重新输入
newType
- 新方法句柄的预期类型
NullPointerException
- 如果任一参数为空
WrongMethodTypeException
- 如果不能进行转换
MethodHandle.asType(java.lang.invoke.MethodType)
public static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder)
给定的数组控制重新排序。 拨打#I
输入参数(值为newType.parameterCount()
,并拨出#O
输出参数数值(值target.type().parameterCount()
),然后重排序数组的长度必须为#O
,每个元素必须为非负数小于#I
对于每N
小于#O
,所述N
个传出参数将被从所拍摄的I
个传入的参数,其中I
是reorder[N]
。
不应用参数或返回值转换。 由newType
确定的每个传入参数的类型必须与目标方法句柄中对应的传出参数或参数的类型相同。 newType
的返回类型必须与原始目标的返回类型相同。
重排序数组不需要指定实际的排列。 如果其索引在数组中出现多次,则传入参数将被重复,如果引用参数的索引未出现在数组中,则引入参数将被删除。 如dropArguments
的情况,在排序数组中未提及的传入参数可以是任何类型,仅由newType
。
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodType intfn1 = methodType(int.class, int.class); MethodType intfn2 = methodType(int.class, int.class, int.class); MethodHandle sub = ... (int x, int y) -> (x-y) ...; assert(sub.type().equals(intfn2)); MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1); MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0); assert((int)rsub.invokeExact(1, 100) == 99); MethodHandle add = ... (int x, int y) -> (x+y) ...; assert(add.type().equals(intfn2)); MethodHandle twice = permuteArguments(add, intfn1, 0, 0); assert(twice.type().equals(intfn1)); assert((int)twice.invokeExact(21) == 42);
target
- 在参数之后调用的方法句柄被重新排序
newType
- 新方法句柄的预期类型
reorder
- 控制重新排序的索引数组
NullPointerException
- 如果任何参数为空
IllegalArgumentException
- 如果索引数组长度不等于目标的arity,或者如果索引数组元素不是newType的
newType
的有效索引,或者如果
target.type()
和
newType
中的两个对应的参数类型不相同,
public static MethodHandle constant(类<?> type, Object value)
在返回方法句柄之前,将传入值转换为请求的类型。 如果请求的类型是原始的,则尝试扩大原始转换,否则尝试参考转换。
返回的方法句柄相当于identity(type).bindTo(value)
。
type
- 所需方法句柄的返回类型
value
- 要返回的值
NullPointerException
- 如果
type
参数为空
ClassCastException
- 如果该值无法转换为所需的返回类型
IllegalArgumentException
- 如果给定的类型是
void.class
public static MethodHandle identity(类<?> type)
type
- 唯一参数的类型和所需方法句柄的返回值
NullPointerException
- 如果参数为空
IllegalArgumentException
- 如果给定类型是
void.class
public static MethodHandle insertArguments(MethodHandle target, int pos, Object... values)
新方法句柄的类型将从原始目标类型中删除绑定参数的类型,因为新方法句柄将不再需要这些参数由其调用者提供。
每个给定的参数对象必须匹配相应的绑定参数类型。 如果绑定的参数类型是一个原语,则参数对象必须是包装器,并且将被取消装箱以产生原始值。
pos
参数选择要绑定的参数。 它可以在零和NL之间(包括),其中N是目标方法句柄的粗细, L是值数组的长度。
target
- 插入参数后调用的方法句柄
pos
- 在哪里插入参数(第一个为零)
values
- 插入的一系列参数
NullPointerException
- 如果目标或
values
数组为空
MethodHandle.bindTo(java.lang.Object)
public static MethodHandle dropArguments(MethodHandle target, int pos, List<类<?>> valueTypes)
pos
参数可以介于零和N之间,其中N是目标的pos
。 如果pos
为零,则虚拟参数将在目标的实参之前; 如果pos
是N,他们会后来。
例:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); assertEquals("xy", (String) cat.invokeExact("x", "y")); MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class); MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2)); assertEquals(bigType, d0.type()); assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
此方法也等效于以下代码:
dropArguments
(target, pos, valueTypes.toArray(new Class[0]))
target
- 删除参数后调用的方法句柄
valueTypes
- 要删除的参数的类型
pos
- 第一个参数的位置(最左边为零)
NullPointerException
- 如果目标为空,或者如果
valueTypes
列表或其任何元素为空
IllegalArgumentException
-如果任何元素
valueTypes
是
void.class
,或者如果
pos
比目标的元数负或更大,或者如果新的方法处理的类型将有太多的参数
public static MethodHandle dropArguments(MethodHandle target, int pos, 类<?>... valueTypes)
pos
参数的范围可以在零和N之间,其中N是目标的pos
。 如果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")); MethodHandle d0 = dropArguments(cat, 0, String.class); assertEquals("yz", (String) d0.invokeExact("x", "y", "z")); MethodHandle d1 = dropArguments(cat, 1, String.class); assertEquals("xz", (String) d1.invokeExact("x", "y", "z")); MethodHandle d2 = dropArguments(cat, 2, String.class); assertEquals("xy", (String) d2.invokeExact("x", "y", "z")); MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class); assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
此方法也等效于以下代码:
dropArguments
(target, pos, Arrays.asList(valueTypes))
target
- 删除参数后调用的方法句柄
valueTypes
- 要删除的参数的类型
pos
- 第一个参数的位置下降(零为最左边)
NullPointerException
- 如果目标为null,或者如果
valueTypes
数组或其任何元素为空
IllegalArgumentException
-如果任何元素
valueTypes
是
void.class
,或者如果
pos
比目标的元数负或更大,或者如果新的方法处理的类型将有
too many parameters
public static MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters)
预处理由filters
数组的元素中指定的一个或多个方法手柄filters
。 过滤器阵列的第一个元素对应于目标的pos
参数,依次类推。
数组中的空参数被视为身份函数,相应的参数保持不变。 (如果数组中没有非空元素,则返回原始目标。)每个过滤器都应用于适配器的相应参数。
如果过滤器F
适用于目标的N
th参数,那么F
必须是一个方法句柄, F
需要一个参数。 F
的唯一参数的类型将替换生成的适应方法句柄中的对象的相应参数类型。 F
的返回类型必须与目标的相应参数类型相同。
如果有filters
(null或not)的元素不对应于目标中的参数位置,则是一个错误。
例:
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
以下是生成的适配器的伪代码:
V 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..., f[i](v[i])..., b...); }
target
- 过滤参数后调用的方法句柄
pos
- 要过滤的第一个参数的位置
filters
-
filters
调用过滤参数的方法句柄
NullPointerException
- 如果目标为null或
filters
数组为空
IllegalArgumentException
- 如果
IllegalArgumentException
的非空元素与
filters
对应的对象参数类型不匹配,或者如果
pos+filters.length
大于
target.type().parameterCount()
,或者如果生成的方法句柄的类型将具有
too many parameters
public static MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter)
如果过滤器返回一个值,则目标必须接受该值作为其位置pos
的参数,在未传递给过滤器的任何参数之前和/或之后。 如果过滤器返回void,则目标必须接受所有不传递给过滤器的参数。 没有参数被重新排序,并且从过滤器返回的结果替换原来传递给适配器的参数的整个子序列(按顺序)。
过滤器的参数类型(如果有)替换了零或一个参数类型的目标,在位置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(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...); void 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
的结果(如果有的话)以外没有coll
,那么collectArguments(mh, 0, coll)
相当于filterReturnValue(coll, mh)
。
如果滤波器方法句柄coll
消耗一个参数并产生无效结果,那么collectArguments(mh, N, coll)
相当于filterArguments(mh, N, coll)
。
其他等价是可能的,但需要参数置换。
target
- 过滤子参数后的方法句柄
pos
- 传递给过滤器的第一个适配器参数的位置和/或接收过滤器结果的目标参数
filter
- 方法句柄来调用参数的子序列
NullPointerException
- 如果任一参数为空
IllegalArgumentException
-如果的返回类型
filter
为非空隙和不一样的
pos
目标的参数,或者如果
pos
不为0之间以及在目标的元数,包括端值,或者如果产生的方法手柄的类型将具有
too many parameters
foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)
,
filterArguments(java.lang.invoke.MethodHandle, int, java.lang.invoke.MethodHandle...)
,
filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)
public static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter)
如果目标返回值,则过滤器必须接受该值作为其唯一参数。 如果目标返回void,则过滤器不能接受参数。
过滤器的返回类型替换生成的适应方法句柄中的目标的返回类型。 过滤器的参数类型(如果有)必须与目标的返回类型相同。
例:
import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle length = lookup().findVirtual(String.class, "length", methodType(int.class)); System.out.println((String) cat.invokeExact("x", "y")); // xy MethodHandle f0 = filterReturnValue(cat, length); System.out.println((int) f0.invokeExact("x", "y")); // 2
以下是生成的适配器的伪代码:
V target(A...); T filter(V); T adapter(A... a) { V v = target(a...); return filter(v); } // and if the target has a void return: void target2(A...); T filter2(); T adapter2(A... a) { target2(a...); return filter2(); } // and if the filter has a void return: V target3(A...); void filter3(V); void adapter3(A... a) { V v = target3(a...); filter3(v); }
target
- 在过滤返回值之前调用的方法句柄
filter
- 方法句柄来调用返回值
NullPointerException
- 如果任一参数为空
IllegalArgumentException
-如果参数列表
filter
不匹配目标的返回类型如上所述
public static MethodHandle foldArguments(MethodHandle target, MethodHandle combiner)
预处理由combiner
,第二个方法句柄。 传递给适配器的参数中,第一个N
参数被复制到组合器,然后被调用。 (这里, 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"));
以下是生成的适配器的伪代码:
// 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
-
combiner
调用传入参数的方法句柄
NullPointerException
- 如果任一参数为空
IllegalArgumentException
- 如果
combiner
的返回类型是无效的并且与目标的第一个参数类型不相同,或者如果目标的初始
N
参数类型(跳过与
combiner
的返回类型匹配的
combiner
)不等同于参数类型为
combiner
public static MethodHandle guardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)
以下是生成的适配器的伪代码:
请注意,测试参数(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...
中的a...)无法通过执行测试进行修改,因此根据需要,从调用者不变地传递到目标或后备。
test
- 用于测试的方法句柄,必须返回布尔值
target
- 如果测试通过,则调用方法句柄
fallback
- 如果测试失败,调用方法句柄
NullPointerException
- 如果任何参数为空
IllegalArgumentException
- 如果
test
不返回布尔值,或者如果所有三种方法类型都不匹配(
test
的返回类型更改为匹配目标)。
public static MethodHandle catchException(MethodHandle target, 类<? extends Throwable> exType, MethodHandle handler)
目标和处理程序必须具有相同的对应参数和返回类型,但处理程序可能会省略尾随参数(与guardWithTest
中的谓词相似 )。 此外,处理程序必须具有额外的前导参数exType
或超类型。
以下是生成的适配器的伪代码:
请注意,保存的参数(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...
中的a...)无法通过执行目标进行修改,如果调用处理程序,则从调用程序到处理程序的引用也不会被修改。
目标和处理程序必须返回相同的类型,即使处理程序总是抛出。 (这可能发生,例如,因为处理程序正在模拟一个finally
子句)。 要创建这样的抛出处理程序,使用throwException
编写处理程序创建逻辑,以创建正确返回类型的方法句柄。
target
- 调用方法句柄
exType
- 处理程序将捕获的异常类型
handler
- 如果抛出匹配的异常,则调用方法句柄
NullPointerException
- 如果任何参数为空
IllegalArgumentException
- 如果
handler
不接受给定的异常类型,或者方法句柄类型在其返回类型及其相应参数中不匹配
public static MethodHandle throwException(类<?> returnType, 类<? extends Throwable> exType)
exType
。
方法句柄将接受exType
的单个参数,并立即将其作为例外。
方法类型将名义上指定返回值为returnType
。
返回类型可能是任何方便的:方法句柄的行为无关紧要,因为它将永远不会正常返回。
returnType
- 所需方法句柄的返回类型
exType
- 所需方法句柄的参数类型
NullPointerException
- 如果任一参数为空