Generated from Example_Goal1_Test.java at 3.0.0 2020-08-11T17:36:18Z

Throwing lambda expressions and interfaces

Abstract

Basic introduction (by example) to Throwing lambda expressions .

Introduction to the issue

Lets consider a method that unfortunately could throw an checked exception:


public static Integer potentiallyThrowing(Integer i) throws CheckedException { return i; // an example }

Following code shows what we would need to do normally to use that method in lambda expression:


@Test public void problemToSolve() { long result = integerList.stream().filter(i -> { try { return potentiallyThrowing(i) != null; } catch (CheckedException e) { throw new RuntimeException(e); } }).count(); assertThat(result).isEqualTo(10); }

We can eventually minimize this to some method that encloses the exception handling and then use this method by reference.


private static boolean myMethodToReference(Integer i) { try { return potentiallyThrowing(i) != null; } catch (CheckedException e) { throw new RuntimeException(e); } } @Test public void problemToSolve2() { long result = integerList.stream().filter(Example_Goal1_Test::myMethodToReference).count(); assertThat(result).isEqualTo(10); }

But doing that in every place, sometimes if not always, asks for an better solution. The immediate effect of having less boilerplate code by replacing anonymous classes by lambda expressions is drastically limited when checked expressions comes into the equation. Of course you can always go with only using unchecked exceptions, but in most cases it is not up to you (e.g. Java JRE, or 3rd party libraries have them anyway).

Solution

What this library introduces is actual functional interfaces that intercepts checked exception and wrap them to NestedException.

So now you can have something like this:


@Test public void checkedExceptionPropagated() throws CheckedException { assertThatThrownBy(() -> { LPredicate<Integer> predicateX = i -> throwingAlways(i) != null; predicateX.test(10); }) .isInstanceOf(NestedException.class) .hasCauseInstanceOf(CheckedException.class); }

Each such interface has some default and static methods that can help to use those interfaces. Here an example what you can do when you need JRE Predicate that handles (wraps) the exceptions.


@Test public void standardPredicateWithExceptionWrapping_short() { long result = integerList.stream().filter(LPredicate.pred(i -> potentiallyThrowing(i) != null)).count(); assertThat(result).isEqualTo(10); }

What happens is very simple. The LPredicate.pred method is actually only forcing compiler to use more specialized functional interface than the JRE one. Each JRE functional interface (from java.util.function package) is extended by appropriate functional interface from this library. The library provides default implementation for the methods of the JRE interfaces with methods that handles the checked exception.

If an checked exception will rise in place where this expression is used as normal Predicate then this wil happen:

In case you need, you could also wrap existing JRE Predicate.


public static LPredicate<Integer> example(Predicate<Integer> predicateStd) { return LPredicate.wrap(predicateStd); }

Addition effects

You could opt for re-throwing checked exception as runtime one (yes, it is not elegant - but it is there in case you want it):


@Test public void rethrowLikeRuntimeException() { byte[] input = new byte[0]; LConsumer.cons((byte[] in) -> new ByteArrayInputStream(in).close()).shovingAccept(input); }

There is also a method to reverse above effect (just in case it is needed):


@Test public void quickNestException() { byte[] input = new byte[0]; LConsumer.cons((byte[] in) -> new ByteArrayInputStream(in).close()).nestingAccept(input); // or simply: LConsumer.tryAccept(input, in -> new ByteArrayInputStream(in).close()); }

More about exception handling id documented here.

Generated from Example_Goal1_Test.java at 3.0.0 2020-08-11T17:36:18Z