513. Java 方法句柄 - 异常处理
在使用 MethodHandle 调用方法时,有一个重要的特点:
无论是 invokeExact 还是 invoke,它们都声明抛出 Throwable。
这意味着被调用的方法可能抛出任何异常,调用方必须显式捕获或继续抛出。
为了简化异常处理,MethodHandles API 提供了一些工具方法,例如 catchException 和 tryFinally。它们可以帮助我们把异常捕获或清理逻辑封装进方法句柄中。
1. catchException —— 捕获异常并处理 🛡️
catchException 可以把一个目标方法句柄包裹起来,并在发生特定异常时交给另一个“异常处理”方法句柄处理。
示例
假设我们有两个方法:
-
problematicMethod(String):业务逻辑,可能抛出IllegalArgumentException。 -
exceptionHandler(IllegalArgumentException, String):异常处理逻辑,返回一个兜底结果。
public static int problematicMethod(String argument) throws IllegalArgumentException {
if ("invalid".equals(argument)) {
throw new IllegalArgumentException();
}
return 1;
}
public static int exceptionHandler(IllegalArgumentException e, String argument) {
System.out.println("Handled IllegalArgumentException for argument = " + argument);
return 0; // 返回兜底结果
}
我们用 catchException 包裹:
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle methodHandle = lookup.findStatic(
Example.class,
"problematicMethod",
MethodType.methodType(int.class, String.class));
MethodHandle handler = lookup.findStatic(
Example.class,
"exceptionHandler",
MethodType.methodType(int.class, IllegalArgumentException.class, String.class));
MethodHandle wrapped = MethodHandles.catchException(methodHandle, IllegalArgumentException.class, handler);
System.out.println(wrapped.invoke("valid")); // 输出 1
System.out.println(wrapped.invoke("invalid")); // 输出 0,并触发异常处理逻辑
👉 相当于在 problematicMethod 外层自动加了一个 try-catch。
2. tryFinally —— 添加清理逻辑 🧹
tryFinally 用于在方法调用的前后添加 清理逻辑(类似 finally 块)。
即使发生异常,finally 块也会执行。
示例
定义一个清理方法 cleanupMethod:
它会在目标方法结束后执行,无论是否发生异常。
public static int cleanupMethod(Throwable e, int result, String argument) {
System.out.println("Inside finally block. Exception = " + e);
return result; // 保持返回值不变
}
用 tryFinally 包裹:
MethodHandle cleanupMethod = lookup.findStatic(
Example.class,
"cleanupMethod",
MethodType.methodType(int.class, Throwable.class, int.class, String.class));
MethodHandle wrappedWithFinally = MethodHandles.tryFinally(methodHandle, cleanupMethod);
System.out.println(wrappedWithFinally.invoke("valid"));
// 输出:Inside finally block
// 1
System.out.println(wrappedWithFinally.invoke("invalid"));
// 输出:Inside finally block
// 然后抛出 IllegalArgumentException
3. 总结 🎯
-
catchException👉 相当于给方法加上 try-catch,能对特定异常定制处理逻辑。 -
tryFinally👉 相当于加上 try-finally,能确保清理逻辑一定执行(比如释放资源、记录日志)。
📌 直观比喻:
-
catchException就像一张 安全气囊,当发生指定异常时帮你兜底。 -
tryFinally就像一个 保洁员,无论是否出错,它都要来打扫一下。