I have been fascinated with Scott WLaschin's Railway Oriented Programming model of handling exceptions: have a side channel, where all the bad stuff will be processed, and keep the good stuff on the main track. Picture below:
A common pattern that comes up in daily code is like :
How to do this in a way that resembles the railway-oriented model discussed above.
Somjit's answer shows correct approach however it uses an outer variable (errors
) to accumulate the errors. This is, in general, discouraged since we should avoid the global/external state.
You can use vavr's partition
method to split the stream into two: one with errors and one with validated ints. They are both put into a tuple:
public void composeExceptions() {
final Tuple2<Stream<Either<IllegalArgumentException, Integer>>, Stream<Either<IllegalArgumentException, Integer>>> both = Stream.range(1, 11)
.map(this::validate)
.partition(Either::isLeft);
both._1.map(Either::getLeft).forEach(e -> System.out.println("Got error: " + e.getMessage()));
both._2.map(Either::get).forEach(i -> System.out.println("Validated correctly: " + i));
}
EDIT Actually there also other options like:
Stream
.range(1, 11)
.map(this::validate)
.toJavaStream()
.collect(Collectors.teeing(
Collectors.filtering(Either::isLeft, toList()),
Collectors.filtering(Either::isRight, toList()),
(errors, ints) -> new Tuple2<>(errors.stream().map(Either::getLeft), ints.stream().map(Either::get))));
which uses teeing
which is quite interesting collector from java API. Unfortunately it mixes vavr and java API which is not great, not terrible.
And:
Stream
.range(1, 11)
.map(this::validate)
.collect(
() -> new Tuple2<>(List.<RuntimeException>empty().asJavaMutable(), List.<Integer>empty().asJavaMutable()),
(tuple, either) -> {
either.peekLeft(tuple._1::add);
either.peek(tuple._2::add);
},
(t1, t2) -> {
t1._1.addAll(t2._1);
t1._2.addAll(t2._2);
}
)
.map((exceptions, integers) -> new Tuple2<>(List.ofAll(exceptions), List.ofAll(integers)));
which uses vavr API only but underneath uses java List
since a mutable structure is required here.