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.

1
  • Note that with your first solution you never close the BufferedRead, causing a memory leak. Commented Nov 3, 2016 at 7:16

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

"I can only use java.util.function"
@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.
Seems you're confusing me with OP.
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()); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.