About

Thursday, October 7, 2021

Use jOOλ’s Sneaky Throw to Avoid Checked Exceptions

Don’t you hate how you have to wrap checked exception throwing code in static initialisers? E.g. you cannot write this in Java:

public class Test {
    static final Class<?> klass = Class.forName("org.h2.Driver");
}

There’s an unhandled ClassNotFoundException, and you can’t catch / rethrow it simply. A static initialiser is needed:

public class Test {
    static final Class<?> klass;

    static {
        try {
            klass = Class.forName("org.h2.Driver");
        }
        catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}

Yuck.

Luckily, one of jOOλ’s lesser known features is the Sneaky class, which contains a bunch of utility methods that wrap a JDK functional interface to an equivalent, “sneaky-throwing” functional interface that doesn’t declare the checked exception.

In short, you can write:

public class Test {
    static final Class<?> klass = Sneaky.supplier(
        () -> Class.forName("org.h2.Driver")
    ).get();
}

The exception is simply re-thrown “sneakily”, as the JVM doesn’t care about an exception’s checked-ness. If you don’t have H2 on your classpath, you’ll get:

Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.ClassNotFoundException: org.h2.Driver
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:375)
        at org.jooq.test.util.Test.lambda$0(Test.java:44)
        at org.jooq.lambda.Unchecked.lambda$supplier$38(Unchecked.java:1695)
        at org.jooq.test.util.Test.<clinit>(Test.java:44)

You can use this approach wherever else a JDK functional interface is required, and you don’t care about an exception’s checked-ness, e.g. in streams:

// Doesn't compile:
Stream
    .generate(
        () -> Class.forName("org.h2.Driver"))
    .limit(1)
    .forEach(System.out::println);

// So ugly
Stream
    .generate(
        () -> {
            try {
                return Class.forName("org.h2.Driver");
            }
            catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        })
    .limit(1)
    .forEach(System.out::println);

// Use jOOλ's Sneaky supplier
Stream
    .generate(Sneaky.supplier(
        () -> Class.forName("org.h2.Driver")))
    .limit(1)
    .forEach(System.out::println);

Get jOOλ here: https://github.com/jOOQ/jOOL



from Java, SQL and jOOQ. https://ift.tt/3BnL3y6
via IFTTT

No comments:

Post a Comment