我创建了一个“生产者”接口(分别与方法引用一起使用,可以轻松地用于单元测试):
@FunctionalInterface
public interface Factory<R, T, X extends Throwable> {
public R newInstanceFor(T t) throws X;
}
我这样创建的,因为我的第一个用例实际上不得不抛出一些选中的WhateverException
。
但是我的第二个用例没有抛出X。
让编译器满意的最好方法是:
Factory<SomeResultClass, SomeParameterClass, RuntimeException> factory;
可以编译,并且可以满足我的需求,但是仍然很丑陋。有没有办法保留单个接口,但是在声明特定实例时不提供X?
答案 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;
}
您随时可以在调用函数中捕获异常并检查类型。