Java 8: Lambda-Streams, Filter by Method with Exception

Java 8: Lambda-Streams, Filter by Method with Exception

You must catch the exception before it escapes the lambda:

s = s.filter(a -> {
try {
return a.isActive();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});

Consider the fact that the lambda isn't evaluated at the place you write it, but at some completely unrelated place, within a JDK class. So that would be the point where that checked exception would be thrown, and at that place it isn't declared.

You can deal with it by using a wrapper of your lambda that translates checked exceptions to unchecked ones:

public static <T> T uncheckCall(Callable<T> callable) {
try {
return callable.call();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

Your example would be written as

return s.filter(a -> uncheckCall(a::isActive))
.map(Account::getNumber)
.collect(toSet());

In my projects I deal with this issue without wrapping; instead I use a method which effectively defuses compiler's checking of exceptions. Needless to say, this should be handled with care and everybody on the project must be aware that a checked exception may appear where it is not declared. This is the plumbing code:

public static <T> T uncheckCall(Callable<T> callable) {
try {
return callable.call();
} catch (Exception e) {
sneakyThrow(e);
return null; // Unreachable but needed to satisfy compiler
}
}

public static void uncheckRun(RunnableExc r) {
try {
r.run();
} catch (Exception e) {
sneakyThrow(e);
}
}

public interface RunnableExc {
void run() throws Exception;
}

@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
throw (T) t;
}

and you can expect to get an IOException thrown in your face, even though collect does not declare it. In most, but not all real-life cases you would want to just rethrow the exception, anyway, and handle it as a generic failure. In all those cases, nothing is lost in clarity or correctness. Just beware of those other cases, where you would actually want to react to the exception on the spot. The developer will not be made aware by the compiler that there is an IOException to catch there and the compiler will in fact complain if you try to catch it because we have fooled it into believing that no such exception can be thrown.

Using lambda to filter stream and throw an exception

First of all, if the set is empty, the lambda passed to forEach won't be executed: an empty stream is empty, and filtering it won't add any element to it. Only potentially remove some.

Second, the lambda creates an exception. But it doesn't throw it.

You can use

if (clients.isEmpty() || clients.stream().anyMatch(client -> !myMay.containsKey(client))) {
throw new InvalidClientException();
}

EDIT: I missed the fact that you wanted to pass the (first?) client not in the set to the exception. To do that, you can do

if (clients.isEmpty()) {
throw new InvalidClientException();
}

clients.stream()
.filter(client -> !myMay.containsKey(client))
.findAny() // or .findFirst()
.ifPresent(client -> {
throw new InvalidClientException(client);
});

That will only work if the exception is a runtime exception, though, because you can't throw a checked exception from a Consumer. If it's a checked exception and you really want to keep it a checked exception, you can use

if (clients.isEmpty()) {
throw new InvalidClientException();
}

Optional<String> wrongClient =
clients.stream()
.filter(client -> !myMay.containsKey(client))
.findAny();
if (wrongClient.isPresent()) {
throw new InvalidClientException(wrongClient.get());
}

Need to continue filtering Java stream when map throws exception after filter and findFirst

You have to move the findFirst to the very end, because it reduces the stream to just (at most) a single element and you cannot "go back" and get more after that.

return myList
.stream()
.filter(Objects::nonNull)
.filter( ... )
.map( ... ) // returns null on Exception, so filter again
.filter(Objects::nonNull)
.findFirst()

How to throw an exception from a stream after a filtering operation

If you really want to throw an exception if no elements match the first filter (as you mention in the comments), you will have to do it in 2 steps:

final List<StatusLiquidation> withCorrectStatus = statusLiquidationsFromPegaDictionary
.stream()
.filter(statusLiquidation -> statusCode.equals(statusLiquidation.getId()))
.collect(toList());

if (withCorrectStatus.isEmpty()) {
throw new Exception("Nothing found");
}

return withCorrectStatus.stream()
.anyMatch(statusLiquidation -> statusLiquidation.getDecl().equals("N"));

Handle checked exceptions in Java8 streams

You've basically listed two viable options.

One more option is to make the checked exceptions be thrown out of the stream processing function ("propagate" or "sneak" a checked exception). This is done by catching a checked exception and re-throwing it as a RuntimeException (by casting). Take a look at this great answer for details.

Multiple libraries have been developed to deal with exception handling in stream API.
For example, you may take a look at the NoException library: https://noexception.machinezoo.com/

It gives you a convenient way to wrap / sneak / log / ignore checked or unchecked exceptions.

For example, in your case it would be:

.map(value -> Exceptions.sneak().function(mapper::doMap))

or

.map(value -> Exceptions.wrap().function(mapper::doMap))

P.S.: I'm NOT the author of the library, nor a contributor, but I've used this library in several projects.

Java 8 - stream - method in filter has unhandled exception, try catch is expecting return statement

As you are filtering, if the isValid method throws a javax.naming.NamingException, apart from logging the exception, you might want to return false:

Set<Whatever> result = list.stream()
.filter(a -> !StringUtils.isEmpty(a.getProp1()))
.filter(a -> !a.getProp1().matches("(.*)xyz"))
.filter(a -> {
try {
return isValid(a.getProp1());
} catch (javax.naming.NamingException e) {
logger.error("Error");
return false;
}})
.collect(Collectors.toCollection(HashSet::new));

This is because the Predicate argument passed to the Stream.filter method must always return a boolean value, no matter if it has catched an exception or not.

handle exceptions in stream java 8

Currently, if an exception occurs no result will be returned hence the compilation error. You'll need to return a value after the catch block .

Java 8 Streams - Filter More Than One Condition

Simple enough

resultList.stream()
.filter(fixture -> fixture.getHome().equals(team) || fixture.getAway().equals(team)))
.collect(toList());

EDIT: This is on the assumption that order does not matter to you. If your final list needs to have home result and then away, have a look at Elliott Frisch's answer.



Related Topics



Leave a reply



Submit