如何不抛出一般指定的异常?

时间:2018-07-31 11:24:13

标签: java generics exception type-conversion throwable

我创建了一个“生产者”接口(分别与方法引用一起使用,可以轻松地用于单元测试):

@FunctionalInterface
public interface Factory<R, T, X extends Throwable> {
    public R newInstanceFor(T t) throws X;
}

我这样创建的,因为我的第一个用例实际上不得不抛出一些选中的WhateverException

但是我的第二个用例没有抛出X。

让编译器满意的最好方法是:

Factory<SomeResultClass, SomeParameterClass, RuntimeException> factory;

可以编译,并且可以满足我的需求,但是仍然很丑陋。有没有办法保留单个接口,但是在声明特定实例时不提供X?

6 个答案:

答案 0 :(得分:12)

您无法使用Java做到这一点。唯一的方法是创建一个子接口。

public interface DefaultExceptionFactory<R, T>
        extends Factory<R, T, RuntimeException>

答案 1 :(得分:12)

做到这一点的唯一方法是子类化-但我敢打赌你知道这一点。为了使我的论点更强一点,请查看扩展了BinaryOperator的{​​{1}}。

答案 2 :(得分:5)

这更像是“社会工程学”的答案:我们在lambda表单上放置了一个合同,该合同不抛出任何东西:

public interface Factory<T, R, X> {

    public R newInstanceFor(T arg) throws X;

    public static Factory<R, U, AssertionError> neverThrows(Factory<U, V, ?> input) {
        return u -> {
            try {
                return input.newInstanceFor(u);
            }
            catch(Throwable t) {
                throw new AssertionError("Broken contract: exception thrown", t);
            }
        };
    }
}

用法是这样的,或者类似:

class MyClass {
    Factory<MyInput, MyOtherClass, AssertionError> factory;

    MyClass(Factory<MyInput, MyOtherClass, ?> factory) {
        this.factory = Factory.neverThrows(factory);
    }

    public void do() {
      factory.newInstanceFor(new MyInput()).do();
    }
}

这种方法的缺点:您不能真正在类型签名中指定合同,因此合同就是实现细节。如果要使用类型签名,则需要第二个子接口。

答案 3 :(得分:3)

如果可能,您可以将方法定义为通用方法,如以下代码所示:

@FunctionalInterface
public interface Factory<R, T> {
    public <X extends Throwable> R newInstanceFor(T t) throws X;
}

答案 4 :(得分:0)

您可以使用龙目岛项目@SneakyThrows批注:

@FunctionalInterface
public interface Factory<R, T> {

    @SneakyThrows
    R newInstanceFor(T t);
}

这允许您引发任何异常(选中或未选中)。但是请阅读文档,因为必须谨慎处理此功能。

答案 5 :(得分:-3)

是否必须使异常通用?为什么不将接口定义为

@FunctionalInterface
public interface Factory<R, T> {
    public R newInstanceFor(T t) throws Throwable;
}

您随时可以在调用函数中捕获异常并检查类型。