Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

noException in Stream Operations

DZone's Guide to

noException in Stream Operations

Java's focus on backward compatibility means relying on coding techniques over language features sometimes. Let's look at handling exceptions in stream operations.

· Java Zone
Free Resource

The single app analytics solutions to take your web and mobile apps to the next level.  Try today!  Brought to you in partnership with CA Technologies

Say you just refactored a huge and complex loop to a more readable stream expression, forgetting that some of the method calls throw an exception. The method containing this code throws this exception, and it is declared in the method head. You do not want to deal with this exception on this level. It is cared about at higher levels of the call stack. And you get that annoying error like a splinter under the nail.

Say you want to convert strings to IP addresses.

private static final String[] allowed = {"127.0.0.1", "::1"};
 
...
 
Arrays.stream(allowed)
      .map(InetAddress::getByName)
      .collect(Collectors.toSet());


The problem is that getByName(String host) throws UnknownHostException. This is not a RuntimeException, so it has to be checked, but the method map() needs a Function as an argument, and Function does not throw any exception. We need a version of getByName that does not throw an exception (or we need to use a different language that is more lame with exceptions).

Arrays.stream(allowed)
       .map(s -> {
                   try {
                     return InetAddress.getByName(s);
                     } catch (UnknownHostException e) {
                     throw new RuntimeException(e);
                     }
                 }).collect(Collectors.toSet());


This is just uglier and messier than the original loop was. Could this try/catch whatever thing be put into a utility class and call some lame static method that wraps the actual call? Kind of, yes. Import the following method statically:

    public interface ExceptionalSupplier<T> {
        T apply() throws Exception;
    }
...
    public static <T> T lame(ExceptionalSupplier<T> z) {
        try {
            return z.apply();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


After the import, you can write:

Arrays.stream(allowed)
      .map(s -> lame(() -> InetAddress.getByName(s)))
      .collect(Collectors.toSet());


The catch is that you can not just lame( ... ) the call. You have to convert it to an exceptional supplier: a functional interface that has the same look-alike as Supplier but that allows exceptions.

Still not ideal. (Well, it is Java, so what did you expect?) Okay. It is Java, but it still can be made better. What if instead of converting the expression through a supplier to an expression that is not throwing the exception, we could convert the “Function” that throws the exception into one that is not throwing the exception. We need a method that accepts an exceptional function and returns a normal function. That way, we can save the () -> noise in our code. Readability rulez.

    public interface ExceptionalFunction<T, R> {
        R apply(T r) throws Exception;
    }
...
    public static <T, R> Function<T, R> lame(ExceptionalFunction<T, R> f) {
        return (T r) -> {
            try {
                return f.apply(r);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        };
    }


With that utility, the “final” expression will be:

Collection<InetAddress> allowedAddresses =
        Arrays.stream(allowed)
              .map(lame(InetAddress::getByName))
              .collect(Collectors.toSet());


The actual utility class in the GIST defines a WrapperException extending RuntimeException so that you can catch the exception somewhere in the method, like:

public myMethod() throws IOException {
try{
    ... do whatever here we do ...
   } catch (RuntTimeExceptionWrapper.WrapperException we) {
       throw (IOException) we.getCause();
   }


That way, the method will throw the exception, but if there is another RuntimeException anywhere, that will be thrown up uncaught.

This is just a simple, nice little trick that helps you keep up with Java, which is backward compatible — instead of starting development with some other language that is modern, clutter-free, and lets you focus more on the functionality you need to code instead of coding techniques.

CA App Experience Analytics, a whole new level of visibility. Learn more. Brought to you in partnership with CA Technologies.

Topics:
java ,exception handling ,java streams ,readable code ,tutorial

Published at DZone with permission of Peter Verhas, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}