poniedziałek, 15 czerwca 2015

Java 8 lambdas and checked exceptions

The Stream API in Java 8 is a blast. Finally, it is possible to easily write concise, declarative code just with pure JDK. There is one problem though - the limitation that lambdas cannot throw checked exceptions. I am sure there are plenty of good reasons not to do such terrible thing, but honestly: it just pisses off. So, I should do something with it then. First attempt is to wrap the lambda's body with a function which would turn the exception from checked to unchecked one (assuming the TechnicalException extends RuntimeException):

public static <T, R> Function<T, R> unchecked(FunctionWithException<T, R> f) {
  Function<T, R> rf = p -> {
    try {
      return f.invokeIt(p);
    } catch (Exception e) {
      throw new TechnicalException("Exception within lambda expression:", e);
    }
  };
  return rf;
}

and write something like this:

List<File> filesList = ...
filesList.stream()
  .map( unchecked( file -> FileUtils.readFileToString(file, "UTF-8" ) ) )
  .map( .... );

but, it obviously is not working, since the Function::apply(T t) does not throw an exception according to the signature. The solution is to define any other @FunctionalInterface just matching the number of arguments and use it instead, like this:

public static <T, R> Function<T, R> unchecked(FunctionWithException<T, R> f) {
  Function<T, R> rf = p -> {
    try {
      return f.invokeIt(p);
    } catch (Exception e) {
      throw new TechnicalException("Exception within lambda expression:", e);
    }
  };
  return rf;
}

Unfortunatelly, depending on the later usage, we may need multiple versions for different interfaces from java.util.function, but we can hide this ughliness in some class :)