Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to not throw a generically specified exception?

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?

like image 400
GhostCat Avatar asked Jul 31 '18 11:07

GhostCat


People also ask

How do you avoid throwing exceptions in Java?

The try-catch is the simplest method of handling exceptions. Put the code you want to run in the try block, and any Java exceptions that the code throws are caught by one or more catch blocks. This method will catch any type of Java exceptions that get thrown. This is the simplest mechanism for handling exceptions.

How do you handle specific exceptions?

The order of catch statements is important. Put catch blocks targeted to specific exceptions before a general exception catch block or the compiler might issue an error. The proper catch block is determined by matching the type of the exception to the name of the exception specified in the catch block.

Should I throw generic exception?

Generic exceptions Error, RuntimeException, Throwable and Exception should never be thrown.

What are the 3 types of exceptions?

There are three types of exception—the checked exception, the error and the runtime exception.


4 Answers

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.

like image 123
Eugene Avatar answered Oct 12 '22 23:10

Eugene


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>
like image 22
Leo Aso Avatar answered Oct 12 '22 22:10

Leo Aso


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.

like image 31
M. Prokhorov Avatar answered Oct 12 '22 21:10

M. Prokhorov


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;
}
like image 42
Beno Arakelyan Avatar answered Oct 12 '22 21:10

Beno Arakelyan