513. Java 方法句柄 - 异常处理

513. Java 方法句柄 - 异常处理

在使用 MethodHandle 调用方法时,有一个重要的特点:
无论是 invokeExact 还是 invoke,它们都声明抛出 Throwable
这意味着被调用的方法可能抛出任何异常,调用方必须显式捕获或继续抛出。

为了简化异常处理,MethodHandles API 提供了一些工具方法,例如 catchExceptiontryFinally。它们可以帮助我们把异常捕获或清理逻辑封装进方法句柄中。


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 就像一个 保洁员,无论是否出错,它都要来打扫一下。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容