Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting rid of Try.FatalException and Try.NonFatalException by "sneaky throwing" #1722

Closed
2 tasks
danieldietrich opened this issue Nov 30, 2016 · 6 comments
Closed
2 tasks

Comments

@danieldietrich
Copy link
Contributor

It is possible to throw every type of exception as unchecked exception:

static void testSneaky() {
  final Exception e = new Exception();
  sneakyThrow(e);    //no problems here
}

@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

(Found on StackOverflow)

  • Therefore we are able to get rid of our exception wrappers Try.FatalException and Try.NonFatalException.
  • Additionally we should rethink CheckedFunction*.unchecked() and API.Unchecked(*)
@danieldietrich
Copy link
Contributor Author

danieldietrich commented Apr 23, 2017

Using sneaky throw might lead to and UndeclaredThrowableException when used in conjunction with dynamic proxies.

Example:

import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) throws Throwable {
        new Test().run();
    }

    void run() throws Throwable {
        
        I obj = (I) Proxy.newProxyInstance(
                Test.class.getClassLoader(),
                new Class<?>[] { I.class },
                (proxy, method, args) -> sneakyThrow(new Exception("test")));
        
        // This call throws java.lang.reflect.UndeclaredThrowableException.
        // It could be fixed if I.test() declares 'throws Exception'.
        // Throwing a RuntimeException does not lead to a UndeclaredThrowableException.
        obj.test();
    }

    interface I {
        void test() /* throws Exception */;
    }

    @SuppressWarnings("unchecked")
    static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
        throw (T) t;
    }

}

We should state that in the javadoc when changing Try.get() (which will re-throw the cause in the case of a Failure).

@ravn
Copy link

ravn commented Aug 3, 2017

You should not use sneaky throws as it wrecks the Java design, and is highly frowned upon by the Java architect(s?).

@danieldietrich
Copy link
Contributor Author

Yes, it introduces new problems, like the UndeclaredThrowableException...

@chb0github
Copy link
Contributor

The java "architects" should never have introduced checked exceptions into the compiler - exceptions are not checked in the VM - which is why scala/kotlin can run on the JVM and not have any at all.

If using sneaky throws can introduce an essentially unrecoverable problem then, sadly, it must be excluded. If excluding it means uglier code ... well, welcome to Java. It's a risky proposition in a library

Just my .02$ -

@ravn
Copy link

ravn commented Aug 4, 2017

Please revert to proper handling. It can most likely be done simply by storing the exception in a Throwable (without having looked at the code) and moving forward.

@danieldietrich
Copy link
Contributor Author

@ravn yes, that seems to be the only solution in order to offer a library with predictable behavior.

I created a new issue: #2049

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants