4

I have problem with lambda expression. My code:

public static void main(String[] args) {

    Function<String, String> lambda = path -> {
        String result = null;
        try {
            BufferedReader br = new BufferedReader(new FileReader(path));
            String line;
            while ((line = br.readLine()) != null) {
                result = result + line;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    };
}

I'm trying now to make code like that:

public static void main(String[] args) throws IOException {

    Function<String, String> lambda = path -> {
        String result = null;
        BufferedReader br = new BufferedReader(new FileReader(path));
        String line;
        while ((line = br.readLine()) != null) {
            result = result + line;
        }
        return result;
    };
}

Is that possible? I can use only java.util.function. I try to delete try catch from "lambda" and my "main" method should be catching that Exception.

Ramkrishna Sharma
  • 6,961
  • 3
  • 42
  • 51
J. Carrer
  • 125
  • 1
  • 8

2 Answers2

4

The built-in Function class doesn't allow you to throw unchecked exceptions, as you can see from the signature of the apply() method.

You can however easily define your own @FunctionalInterface that does permit exceptions to be thrown, e.g.:

@FunctionalInterface
public interface CheckedFunction<U,V> {
  public V apply(U u) throws Exception;
}

And make your lambda variable a CheckedFunction instead.


The alternative, if you must use the built-in Function for whatever reason, is to turn all checked exceptions into RuntimeExceptions, e.g.:

Function<Foo,Bar> f = foo -> {
  try {
    return foo.methodThatCanThrow();
  } catch (RuntimeException e) {
    throw e;
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
};

This will allow your code to compile, but is certainly not a generally recommended best practice.

dimo414
  • 47,227
  • 18
  • 148
  • 244
  • "I can only use `java.util.function`" – Marko Topolnik Nov 03 '16 at 07:53
  • @MarkoTopolnik why? What sort of meaningless restriction is that? You cannot throw exceptions from `java.util.function.Function`, and lambdas are *designed* to support defining your own functional interfaces. If you want to use lambdas the way you're using them in your example code, you'll need to use a different interface. – dimo414 Nov 03 '16 at 08:06
  • Seems you're confusing me with OP. – Marko Topolnik Nov 03 '16 at 08:13
2

As dimo414 said, first declare a new functional interface

@FunctionalInterface
public interface CheckedFunction<U, V> {
    public V apply(U u) throws IOException;
}

Then I'll go one step further by refactoring the lambda expression into the following:

CheckedFunction<String, String> lambda = path -> {
            try (BufferedReader br = new BufferedReader(new FileReader(path))) {
                return br.lines().collect(Collectors.joining());
            }
        };

The try-with-resources takes care of closing the BufferedRead in any case and using the conciseness of the stream API to concatenate all the lines.

Going a second step further, you don't even need to bother with BufferedReader anymore if you use Files ! This can be taken down to the following lambda:

CheckedFunction<String, String> lambda = path -> Files.lines(Paths.get(path)).collect(Collectors.joining());
Spotted
  • 4,021
  • 17
  • 33