Java supports checked exceptions from the very start. With Java 8 the language element lambda and the RT library modifications supporting stream operations introduced functional programming style to the language. Functional style and exceptions are not really good friends. In this article, I will describe a simple library that handles exceptions somehow similar to how null is handled using Optional.

The library works (after all it is a single Class and some inner classes, but really not many). On the other hand, I am not absolutely sure that using the library will not deteriorate the programming style of the average programmer. It may happen that someone having a hammer sees everything as a nail. A hammer is not a good pedicure tool. Have a look at this library more like an idea and not as a final tool that tells you how to create perfect code handling exceptions.

Also, come and listen to the presentation of Michael Feathers about exceptions May 6, 2019, Zürich https://www.jug.ch/html/events/2019/exceptions.html

1. Handling Checked Exception

Checked exceptions have to be declared or caught like a cold. This is a major difference from null. Evaluating an expression can silently be null but it cannot silently throw a checked exception. When the result is null then we may use that to signal that there is no value or we can check that and use a "default" value instead of null. The code pattern doing that is

var x = expression;
if( expression == null ){
  x = default expression that is really never null
}

The pattern topology is the same in case the evaluation of the expression can throw a checked exception, although the Java syntax is a bit different:

Type x; // you cannot use 'var' here
try{
  x = expression
}catch(Exception weHardlyEverUseThisValue){
  x = default expression that does not throw exception
}

The structure can be more complex if the second expression can also be null or may throw an exception and we need a third expression or even more expressions to evaluate in case the former ones failed. This is especially naughty in case of an exception throwing expression because of the many bracketing

Type x; // you cannot use 'var' here
try{
  try {
    x = expression1
  }catch(Exception e){
  try {
    x = expression2
  }catch(Exception e){
  try {
    x = expression3
  }catch(Exception e){
    x = expression4
  }}}}catch(Exception e){
  x = default expression that does not throw exception
}

In the case of null handling, we have Optional. It is not perfect to fix the million dollar problem, which is the name of designing a language having null and also an underestimation, but it makes life a bit better if used well. (And much worse if used in the wrong way, which you are free to say that what I describe in this article is exactly that.)

In the case of null resulting expressions, you can write

var x = Optional.ofNullable(expresssion)
         .orElse(default expression that is nere null);

You can also write

var x = Optional.ofNullable(expresssion1)
.or( () -> Optional.ofNullable(expression2))
.or( () -> Optional.ofNullable(expression3))
.or( () -> Optional.ofNullable(expression4))
...
.orElse(default expression that is nere null);

when you have many alternatives for the value. But you cannot do the same thing in case the expression throws an exception. Or can you?

2. Exceptional

The library Exceptional (https://github.com/verhas/exceptional)

<groupId>com.javax0</groupId>
<artifactId>exceptional</artifactId>
<version>1.0.0</version>

implements all the methods that are implemented in Optional, one method more and some of the methods a bit differently aiming to be used the same way in case of exceptions as was depicted above for Optional in case of null values.

You can create an Exceptional value using Exceptional.of() or Exceptional.ofNullable(). The important difference is that the argument is not the value but rather a supplier that provides the value. This supplier is not the JDK Supplier because that one cannot throw an exception and that way the whole library would be useless. This supplier has to be Exceptional.ThrowingSupplier which is exactly the same as the JDK Supplier but the method get() may throw an Exception. (Also note that only an Exception and not Throwable which you should only catch as often as you catch a red-hot iron ball using bare hands.)

What you can write in this case is

var x = Exceptional.of(() -> expression) // you CAN use 'var' here
    .orElse(default expression that does not throw exception);

It is shorter and shorter is usually more readable. (Or not? That is why APL is so popular? Or is it? What is APL you ask?)

If you have multiple alternatives you can write

var x = Exceptional.of(() -> expression1) // you CAN use 'var' here
    .or(() -> expression2)
    .or(() -> expression3) // these are also ThrowingSupplier expressions
    .or(() -> expression4)
...
    .orElse(default expression that does not throw exception);

In case some of the suppliers may result null not only throwing an exception there are ofNullable() and orNullable() variants of the methods. (The orNullable() does not exist in Optional but here it makes sense if the whole library does at all.)

If you are familiar with Optional and use the more advanced methods like ifPresent(), ifPresentOrElse(), orElseThrow(), stream(), map(), flatMap(), filter() then it will not be difficult to use Exceptional. Similar methods with the same name exist in the class. The difference again is that in case the argument for the method in Optional is a Function then it is ThrowingFunction in case of Exceptional. Using that possibility you can write code like

    private int getEvenAfterOdd(int i) throws Exception {
        if( i % 2 == 0 ){
            throw new Exception();
        }
        return 1;
    }

    @Test
    @DisplayName("some odd example")
    void testToString() {
        Assertions.assertEquals("1",
                Exceptional.of(() -> getEvenAfterOdd(1))
                        .map(i -> getEvenAfterOdd(i+1))
                        .or( () -> getEvenAfterOdd(1))
                .map(i -> i.toString()).orElse("something")
        );
    }

It is also possible to handle the exceptions in functional expressions like in the following example:

    private int getEvenAfterOdd(int i) throws Exception {
        if (i % 2 == 0) {
            throw new Exception();
        }
        return 1;
    }

    @Test
    void avoidExceptionsForSuppliers() {
        Assertions.assertEquals(14,
                (int) Optional.of(13).map(i ->
                        Exceptional.of(() -> inc(i))
                                .orElse(0)).orElse(15));
    }

Last, but not least you can mimic the ?. operator of Groovy writing

a.b.c.d.e.f

expressions, where all the variables/fields may be null and accessing the next field through them, causes NPE. You can, however, write

var x = Exceptional.ofNullable( () -> a.b.c.d.e.f).orElse(null);

3. Summary

Remember what I told you about the hammer. Use with care and for the greater good and other BS.


Comments

Please leave your comments using Disqus, or just press one of the happy faces. If for any reason you do not want to leave a comment here, you can still create a Github ticket.