0

In the following code, I wrote throws in the method signature, but again in Lambda for write, the compiler gives an error. Why?

compiler error: Unhandled exception: java.io.IOException

 public void saveTodoItems() throws IOException {

    try (BufferedWriter outputStream = new BufferedWriter(new OutputStreamWriter(
            new FileOutputStream("TodoItems.txt"), StandardCharsets.UTF_8))) {

        todoItems.forEach(todoItem -> {
                outputStream.write(todoItem.getShortDescription() + "\t" //compile error on write
                        + todoItem.getDetail() + "\t"
                        + todoItem.getDeadLine()+"\n");

        });
    }
}
Dave Newton
  • 158,873
  • 26
  • 254
  • 302
vorxd
  • 15
  • 3
  • What is `todoItems`? Some kind of list? And what's the error? – byxor Feb 10 '22 at 13:43
  • @byxor yes it is an array list and the compiler error is: Unhandled exception: java.io.IOException – vorxd Feb 10 '22 at 13:44
  • 3
    `IOException` is a "checked exception". Whatever interface you've implemented with your lambda, it doesn't declare that the method will throw an IOException. You probably need a try/catch inside your lambda – byxor Feb 10 '22 at 13:47
  • @byxor "*Whatever interface you've implemented*" it's forEach of Iterable, so it's just java.util.function.Consumer. – Michael Feb 10 '22 at 13:51
  • Just use a regular for-loop here. – Michael Feb 10 '22 at 13:52

1 Answers1

3

Remember that lambdas are supposed to be implementations of functional interfaces. In this case, forEach takes the functional interface Consumer<T> as a parameter.

void forEach(Consumer<? super T> action)

So your lambda is actually implementing the single abstract method in the Consumer interface - accept. This method is not declared to throw any exceptions:

void accept(T t); // no throws clause here at all!

Therefore, the IOException that the write call could throw is considered to be unhandled. The fact that you have added a throws clause to your saveTodoItems method is irrelevant.

On the other hand, if you have declared your own functional interface that does have a throws clause in its single abstract method:

interface IOConsumer<T> {
    void accept(T t) throws IOException;
}

It is possible to write:

IOConsumer<TodoItem> consumer = todoItem -> {
    outputStream.write(todoItem.getShortDescription() + "\t"
                    + todoItem.getDetail() + "\t"
                    + todoItem.getDeadLine()+"\n");
};

Of course, you would not be able to use this in forEach, because it only accepts a Consumer, not an IOConsumer. You should surround the write with a try...catch, or see here for more alternatives.

Sweeper
  • 213,210
  • 22
  • 193
  • 313