问题
I created a "producer" interface (to be used with method references, respectively to be easily mocked for unit tests):
@FunctionalInterface
public interface Factory<R, T, X extends Throwable> {
public R newInstanceFor(T t) throws X;
}
which I created like that, as my first use case actually had to throw some checked WhateverException
.
But my second use case doesn't have an X to throw.
The best I could come up with to make the compiler happy is:
Factory<SomeResultClass, SomeParameterClass, RuntimeException> factory;
That compiles, and does what I need, but still ugly. Is there a way to keep that single interface, but not provide an X when declaring specific instances?
回答1:
The only way to do it is subclassing - but I bet you knew that. To make my argument stronger, look at BinaryOperator
that extends BiFunction
.
回答2:
You cannot do that in Java. The only way is to create a sub interface.
public interface DefaultExceptionFactory<R, T>
extends Factory<R, T, RuntimeException>
回答3:
This is more of a "social engineering" answer: we place a contract on the lambda form that it doesn't throw anything:
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);
}
};
}
}
Usage is like this, or something along the lines of:
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();
}
}
Downside of this approach: you can't really specify the contract in the type signature, the contract is then an implementation detail. If you want to have this in type signature, you will need a second sub-interface.
回答4:
You can define the method as generic like below code, if it is possible for you:
@FunctionalInterface
public interface Factory<R, T> {
public <X extends Throwable> R newInstanceFor(T t) throws X;
}
回答5:
You can use Project Lombok's @SneakyThrows annotation:
@FunctionalInterface
public interface Factory<R, T> {
@SneakyThrows
R newInstanceFor(T t);
}
This allows you to throw any exception (checked or unchecked). But read the documentation because this feature must be handled with care.
回答6:
Do you have to make the exception generic? Why not define the interface as
@FunctionalInterface
public interface Factory<R, T> {
public R newInstanceFor(T t) throws Throwable;
}
You can always catch your exception and check the type if you need in your calling function.
来源:https://stackoverflow.com/questions/51612250/how-to-not-throw-a-generically-specified-exception