How to not throw a generically specified exception?

好久不见. 提交于 2020-01-01 01:16:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!