Core Java

Handling exceptions functional style

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.

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

1
2
3
4
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:

1
2
3
4
5
6
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
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

1
2
var x = Optional.ofNullable(expresssion)
         .orElse(default expression that does not throw exception);

You can also write

1
2
3
4
5
6
var x = Optional.ofNullable(expresssion1)
.or( () -> Optional.ofNullable(expression2))
.or( () -> Optional.ofNullable(expression3))
.or( () -> Optional.ofNullable(expression4))
...
.orElse(default expression that does not throw exception);

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?

Exceptional

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

1
2
3
<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

1
2
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

1
2
3
4
5
6
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
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:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
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

1
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

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

Summary

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

Published on Java Code Geeks with permission by Peter Verhas, partner at our JCG program. See the original article here: Handling exceptions functional style

Opinions expressed by Java Code Geeks contributors are their own.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
kishore
kishore
4 years ago

what is RT library here , i not understand?

Peter Verhas
Peter Verhas
4 years ago
Reply to  kishore

Run Time

Octavian Nita
Octavian Nita
4 years ago
Reply to  kishore

Probably RunTime…

Back to top button