Stack Exchange
Why does Unhandeled IOException get triggerred in stream.forEach() but not in normal for loop
Unhandeled IOException is trigerred in below code:
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
            zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
            zos.write(files.get(testId));
            zos.closeEntry();
        });

But same is not the case in below code:
ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());    
for (Integer testId : testIds) {
    zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
    zos.write(files.get(testId));
    zos.closeEntry();
}


Both snippets have the same issue regarding unhandled exceptions.

@Tom attaching screenshot for you.

Even the Screenshot doesn't contain the obviously important method header.

In the screenshot u can clearly see that stream.forEach snippet is giving compile time error but same is not the case with other snippet.
And yes, as I said method header throws Exception.

No, you haven't said that. Neither in the question, in one of the edits of the question or in a comment under this question.

It is not specific to forEach.
Checked exceptions thrown in a lambda body has a different behavior than without lambda.

15.27.3. Type of a Lambda Expression
A checked exception that can be thrown in the body of the lambda
  expression may cause a compile-time error, as specified in §11.2.3.

And you can read at this point :

11.2.3. Exception Checking
It is a compile-time error if a lambda body can throw some exception
  class E when E is a checked exception class and E is not a subclass of
  some class declared in the throws clause of the function type targeted
  by the lambda expression.

foreach() takes a Consumer and you can see that accept() defined in doesn't declare any exception :
@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);    
    ...
}

In fact in your imperative style snippet, the enclosing method has a throws IOException or Exception defined such as :
public void doThat() throws IOException {
    ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());    
    for (Integer testId :
                testIds) {
            zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
            zos.write(files.get(testId));
            zos.closeEntry();
    }
}

So the compilation is fine as the checked exception is "handled" : you throw it.
The same thing doesn't work with lambda for explained reason.
As workaround, you have two ways :

not using streams. You should consider this point as it doesn't have a lot added value in your use case
catching the exception.

About the second point, as you cannot throw the IOException from the lambda body, you have to handle it with a catch statement.
If the exception should be propagate to the client, you could re-throw a RuntimeException that wraps the actual one as runtime exceptions don't have the same restriction as checked exceptions in lambda body:
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
           try{
                zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
                zos.write(files.get(testId));
                zos.closeEntry();
            }
            catch(IOException e){
                // log the exception 
                throw new RuntimeException(e);
                // or throw a custom RuntimeException class if it makes more sense
            } 
        });


@Lino  Thank you. I did it !

even better now :)

That is because the signature of method from the interface used in .forEach() (Consumer to be precise) doesn't declare to throw an exception.
The signature looks like the following:
public interface Consumer<T> {
     void accept(T t); // <-- no throws declaration
}

Because of that. Java forbids to throw a checked exception. 
In your second snippet you probably have a method with a throws declaration like the following:
 public void method() throws IOException{ // <-- throws declaration here
     ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());    
     for (Integer testId : testIds) {
         zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
         zos.write(files.get(testId));
         zos.closeEntry();
     }
}    

which is why you don't get a similar error. 
A way to go around this error is to use a try catch inside the .forEach() and then catch the exception but this would just bloat the lambda. I would suggest that you leave your code and just use the iterative for-each loop

JFYI I was changing the old for loop to stream.forEach() and both the snippets is in same method.
And yes method throws Exception.

Finally, almost same content as mine :)

@davidxxx yes it was kind of a race ;)

The exception will be thrown from within the lambda meaning that the caller of the lambda needs to catch/check the exception. I assume that you have a try-catch or throws clause outside your snippet?
Since forEach does not check the exception for you the IOException is unhandled. You must handle it instead. Simplest way to do this is catching the exception and wrapping it (e.g. in a Runtime exception).
ZipOutputStream zos = new ZipOutputStream(outputStream);
testIds.stream().forEach(testId->{
    try{
        zos.putNextEntry(new ZipEntry(testId + "_" + (Calendar.getInstance().getTimeInMillis() / 1000) + ".pdf"));
        zos.write(files.get(testId));
        zos.closeEntry();
    } catch(IOException e) {
        throw new RuntimeException(e)
    }
}


simplest way would be to not use Streams for such an easy operation in the first place

It appears you are closing the stream in the loop. The second time around, the stream is closed.

The OP appears to be getting a compile error because he is not declaring a checked exception. He said IOException...
