If/else representation with stream and Java 8

That's a pretty interesting question, which fortunately I had to face some time ago. Mi approach consisted on declaring a list of Supplier<T> which would be iterated only if there's and exception thrown (the intention of this approach was to retrieve data from DB based on the parameters given, so I would be able to search by id or by an instance).

import java.util.function.Supplier;

public class AbstractFacadeUtil {

    public <R> R tryOr(Supplier<R>...fns) {
        R result = null;
        boolean success = false;
        int i = 0;
        while (!success && i < fns.length) {
            Supplier<R> fn = fns[i++];
            try {
                result = fn.get();
                success = true;
            } catch (Exception e) {

            }
        }
        if (!success) {
            throw new RuntimeException(new Exception(String.format("[%s] Couldn't find a successful method to apply\"", this.getClass())));
        }
        return result;
    }

}

Some notes:

  • I'd used Supplier<T> because it's body didn't contain anything that would throw an undeclared exception which, otherwise, would be needed to use Callable<T> instead.
  • Yeah, could have given it a better name though.
  • Maybe an Iterator<T> would make that piece of code more understandable and clean.

In your specific case, I'd use Jason's approach by adding a Supplier<T> at the end of the list that would throw an NoParserFoundException

[EDIT] Also, you should iterate the List<Supplier<T>> or List<Callable<T>> wheter the Parser can't parse and it throws an CantParseException. So, as you see, exceptions can help a lot even I'm not sure this would be the most efficient or expert approach. Hope it helps you.

[EDIT2] This is an example of how I implemented the solution given above.


You can use simply a forEach if-else inside

parsers.forEach(p -> {
                if (!p.canParse(message)) {
                   System.out.println("I can't parse it!");
                } else {
                    p.parse();
                }
       });

This is a perfect example of when to use the Optional#orElse or the Optional#orElseThrow method(s). You want to check if some condition is met so you filter, trying to return a single result. If one does not exist, some other condition is true and should be returned.

try {
    Parser parser = parsers.stream()
            .filter(p -> p.canParse(message))
            .findAny()
            .orElseThrow(NoParserFoundException::new);

    // parser found, never null
    parser.parse();
} catch (NoParserFoundException exception) {
   // cannot find parser, tell end-user
}

In case only one parser can parse the message at a time you could add a default parser:

class DefaultParser implements Parser {
    public void parse() {
        System.out.println("Could not parse");
    }
    public boolean canParse(String message) {
        return true;
    }
}

And then use it via

// make sure the `DefaultParser` is the last parser in the `parsers`
parsers.stream().filter(p -> p.canParse(message)).findFirst().get().parse();

or alternatively drop the DefaultParser and just do

Optional<Parser> parser = parsers.stream().filter(p -> p.canParse(message)).findFirst();
if (parser.isPresent()) {
    parser.get().parse();
} else {
    // handle it 
}