MethodHandle - 必须被捕获或声明为抛出。为什么会出现这个错误?

3

我有一段Java 7的代码,其中我在使用MethodHandle。代码如下:

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
class HelloWorldApp {
    public static  void main(String[] args) {
    MyMethodHandle obj = new MyMethodHandle();
    obj.getToStringMH();
    }
}

class MyMethodHandle {
    public String getToStringMH() {
        MethodHandle mh;
        String s ;
            MethodType mt = MethodType.methodType(String.class, char.class, char.class);
            MethodHandles.Lookup lk = MethodHandles.lookup();
        try {
            mh = lk.findVirtual(String.class, "replace", mt);
        } catch (NoSuchMethodException | IllegalAccessException mhx) {
            throw (AssertionError)new AssertionError().initCause(mhx);
        }
        try {
            s = (String) mh.invokeExact("daddy",'d','n');
        }
        catch(Exception e) {
            throw (AssertionError)new AssertionError().initCause(e);
        }
        System.out.println(s);
        return "works";
    }
}

当我编译这个时:
javac HelloWorldApp.java

我收到了这样的错误消息:

我遇到了这个错误:

HelloWorldApp.java:23: error: unreported exception Throwable; must be caught or declared to be thrown
            s = (String) mh.invokeExact("daddy",'d','n');
                                       ^
1 error

我哪里犯了错误?


3
你可以将 (AssertionError)new AssertionError().initCause(mhx) 改写为 new AssertionError(mhx) - Peter Lawrey
2个回答

6

正如MethodHandle.invokeExact的Javadoc所述

public final Object invoke(Object... args) throws Throwable

这意味着你必须捕获Throwable或声明你的方法throws Throwable
顺便说一下,由于这会抛出一个通用异常,因此有一个替代方案。
    try {
        s = (String) mh.invokeExact("daddy",'d','n');
    } catch(Throwable t) {
        throw new AssertionError(t);
    }

是将 Throwable 重新抛出

    try {
        s = (String) mh.invokeExact("daddy",'d','n');
    } catch(Throwable t) {
        Thread.currentThread().stop(t); // avoids wrapping the true exception
    }

使用Thread.stop(t)停止另一个线程可能是不可预测的,但如果你为当前线程抛出它,则是可预测的。

注意:你需要确保你的方法“throws”适当的已检查异常,以便于编译器无法确保这一点。


3
此处方法文档所述,使用Thread.stop(Throwable)已经过时且不安全。即使在当前线程中,它的影响也是不可预测的--例如:_"它可能被用于生成目标线程无法处理的异常(包括该线程本来无法抛出的受检异常,若不是因为该方法)"_。 - Ted Hopp
虽然你是正确的,(添加了一个注释)但我不明白通过包装异常来掩盖它会使调用者更容易捕获正确的异常。这就像说,我不知道你能否捕获这个已检查的异常,所以我会确保你不能。 - Peter Lawrey
1
在这种情况下,它可能会抛出一个未经检查的 StringIndexOutOfBoundsException 异常,调用者可能(不太可能)捕获此异常。但如果它被包装在 ErrorRuntimeException 中,这将变得更加困难。 - Peter Lawrey

2

invokeExact 被声明为 throws Throwable,因此需要捕获 Throwable 而不是 Exception。(Exception 只是 Throwable 的一种)。

try {
    s = (String) mh.invokeExact("daddy",'d','n');
}
catch(Throwable t) {
    throw new AssertionError(t);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接