I have a case where I need to
map an object, if the mapping function throws an exception, I map it to null.filter the mapped stream for null object, if null then throw Exception, else collect to List.How would I achieve this?
list.stream().map(ob-> {
try {
// cannot throw only catch
return function(ob);
} catch (Exception e) {
log.error(e);
return null;
}
}).filter(Objects::isNull).findFirst().orElseThrow(Exception::new);
Now my question is how should I tweak/refactor the above lambda to throw new Exception() on null or else collect(Collectors.toList()).
If you intend to report the exception (which is a good idea), you should never map it to null in the first place. Since certain functional interfaces do not allow to throw a checked exception, you should rethrow it wrapped in an unchecked exception:
try {
List<Object> result = list.stream().map(ob-> {
try {
// cannot throw checked exception types
return function(ob);
} catch(Exception e) {
throw new CompletionException(e);
}
}).collect(Collectors.toList());
} catch(CompletionException ex) {
throw (Exception)ex.getCause();
}
The key point is that this will throw the original exception, with all information contained within it, instead of creating a new instance via new Exception() that would contain no information about the cause at all.
Note that for some cases, there are already dedicated exception types, e.g. UncheckedIOException to wrap an IOException. In other cases, it might be cleaner to declare your own unchecked exception type, to be sure that it doesn’t get mixed up with other exceptions thrown by other components of your application.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With