在没有抛出声明的情况下从泛型方法传播异常

时间:2013-03-07 14:34:34

标签: java exception

我有一个简单的界面

public interface Func<I, O> {
    public O apply(I i);
}

我有一个带有一堆私有(静态)类的类,它实现了这样的接口,如此

import org.json.*;
public static class Baz {
    public static B Qux(String jsonSource) throws JSONException {
        JSONObject m = new JSONObject(jsonSource);
        return new Baz.Foo().apply(m);
    }

    private static class Foo implements Func<JSONObject, B> {
        public B apply(JSONObject f) {
            JSONObject x = f.getJSONObject("bar");
            /* Whatever other code in here */
            return new B(); /* Place-holder */
        }
    }
}

由于JSONObjects上的任何操作都需要捕获JSONException,因此编译器会在JSONObject x = f.getJSONObject("bar");处抱怨未捕获和未声明的异常。考虑到我可以简单地将该特定内容应用于try-catch并重新抛出调用者的异常,我尝试了它,如下所示:

private static class Foo implements Func<JSONObject, B> {
    public B apply(JSONObject f) {
        try {
            JSONObject x = f.getJSONObject("bar");
            /* Whatever other code in here */
            return new B(); /* Place-holder */
        catch (JSONException e) {
            throw e;
        }
    }
}

然而,有了这个,我现在error: unreported exception JSONException; must be caught or declared to be thrown指向throw e;

我不明白为什么这不起作用。如预期的那样,进一步将呼叫包裹到apply没有任何新的内容。

我的问题是:

  1. 为什么这不起作用?
  2. 我该如何解决?
  3. 我相信解决方法是让我的界面接受异常类型。我不确定这种语法是否有效,但我想我可以按照

    的方式做一些事情
    public interface FuncEx<I, O, E> {
        public O apply(I i) throws E;
    }
    

    有更好的方式吗?我不认为我必须创建一个全新的界面才能解决这个问题。

1 个答案:

答案 0 :(得分:4)

检查异常(即不是RuntimeException的子级的异常 - 如JSONException)构成方法签名的一部分。如果您调用抛出已检查异常的方法,则必须处理它,或声明您自己抛出它。如果你自己抛出一个检查过的异常(就像你使用catch / rethrow代码那样),你仍然必须声明它。

如果您不想声明抛出它,则可以将其包装在RuntimeException中。例如:

private static class Foo implements Func<JSONObject, B> {
  public B apply(JSONObject f) {
    try {
        JSONObject x = f.getJSONObject("bar");
        /* Whatever other code in here */
        return new B(); /* Place-holder */
    catch (JSONException e) {
        throw new RuntimeException("Could not get bar", e);
    }
  }
}

关于何时抛出已检查的异常而不是RuntimeExceptions的想法有很多种。对我来说,我的第一个指导原则是,如果你能够合理地期望调用者以有意义的方式响应异常(而不仅仅是重新抛出它),那么将它作为一个经过检查的异常。否则使它成为RuntimeException。

这是一篇关于这个主题的优秀文章:http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html