bigywater.tech
Java · 333

MethodHandle 组合器:把调用逻辑组合成句柄

MethodHandle 能把小函数像积木一样拼成复杂的调用逻辑。每个组合器到底改了方法类型的哪一部分?写错类型会得到什么异常?拼出来的句柄慢不慢?这篇逐个运行,并量出 static final 与局部句柄的差别。

0.58 vs 2.26 ns
static final 句柄与局部变量里的句柄的 invokeExact 耗时(直接调用也是 0.58 ns)
10 个以上
本文实际运行的组合器 / 适配方法数
void != int
tryFinally 清理句柄返回类型与目标不匹配时的异常信息

组合器逐个运行

实测 · 本机执行输出
1 基础:add 的类型 (int,int)int;invokeExact(2,3) = 5
2 insertArguments(add, 0, 10):类型 (int)int;(5) = 15
3 dropArguments(add, 0, String):类型 (String,int,int)int;("忽略",2,3) = 5
4 filterArguments(add, 0, twice):先把第 1 个参数翻倍。类型 (int,int)int;(3,4) = 10(2*3+4=10)
5 filterReturnValue(len, twice):类型 (String)int;("abcd") = 8(4*2)
6 guardWithTest:类型 (int)String;(5) = 正数 5;(-2) = 非正数 -2
7 catchException(parse, NumberFormatException, fallback):("42") = 42;("abc") = -1
8a tryFinally 的清理句柄类型不匹配:IllegalArgumentException: target and return types must match: void != int
8 tryFinally(清理句柄必须返回与目标相同的类型):
      [cleanup] t=null r=7
    ("7") = 7
      [cleanup] t=NumberFormatException r=0
    ("zz") 抛出 NumberFormatException(cleanup 已先执行)
9 permuteArguments(greet, 交换两个参数):("小明","你好") = 你好, 小明!
10 foldArguments(sum3, 0, add):类型 (int,int)int;(1,2) = 6(先算 add(1,2) = 3 放到最前面,再 sum3(3, 1, 2) = 6)
11 collectArguments(add, 0, len):类型 (String,int)int;("abc",10) = 13(3+10)
12 asSpreader(int[], 2):类型 (int[])int;({4,5}) = 9
13 asVarargsCollector:isVarargsCollector=true;invoke(1,2,3) = [1, 2, 3];invoke() = []
14 countedLoop(0..4 累加):类型 ()int;() = 10(0+1+2+3+4)
15 asType 把 int 适配成 long/Integer/Object:3,3
16 invokeExact 类型不精确:WrongMethodTypeException: handle's method type (int,int)int but found (Object,Object)void
17 insertArguments 类型错误:ClassCastException: class java.lang.Integer is not compatible with class java.lang.String
18 identity/zero/empty/constant:原样,0,(String)void,固定值
19 组合句柄 (x) -> (1 + x) * 2 的调用耗时:直接 Java 方法 0.58 ns;static final 句柄 invokeExact 0.58 ns;非 static final 的局部句柄 invokeExact 2.26 ns;invoke(类型适配)4.61 ns(s=0)

分步演示

MethodHandle 组合器
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12;性能数字是自写计时循环取 3 次的最小值,不是 JMH
    • 没有验证:whileLoop / doWhileLoop / iteratedLoop 的完整用法(我写的 whileLoop 例子有类型错误,已删除,没有展示)、loop 的通用形式、arrayElementGetter / varHandle 系列、MethodHandleProxies、LambdaForm 与 JIT 内联的底层细节、JDK 27 上的行为差异
    京ICP备2026067502号-1京公网安备11010502063487号