Search code examples
javafilelambda

error: unreported exception IOException; must be caught or declared to be thrown in stream()


I'm trying to write a File and here is the code:

    public static void writeFile(File f, int n) throws IOException{
    //reads n teams which go to next phase

    try(BufferedWriter writer = new BufferedWriter(new FileWriter(f))){
        table.stream()
         .sorted()
         .limit(n)
         .forEachOrdered(x->writer.write(x.getName()));
        /*for(int i=0;i<n;i++){
            writer.write(table.get(i).getName());
            writer.newLine();
        }*/ this if uncommented works great!
    }catch (IOException e){
        e.printStackTrace();
    }
}

and I get this error when I try to compile:

Counter.java:123: error: unreported exception IOException; must be caught or declared to be thrown .forEachOrdered(x->writer.write(x.getName()));

My doubt: Even if I declare the IOException in the method I am using the .forEachOrdered() I can't use it because the method which I define inside the .forEachOrdered() (which is a Consumer) doesn't declare it? I don't know if I am clear, but maybe you could infer something just looking at the code. Thanks.

Note: the table is a declared static list with Teams.


Solution

  • The problem is that the signature for forEachOrdered requires a Consumer and a Consumer does not declare that its accept method can throw any checked exceptions.

    JLS 11.2.3 says:

    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.

    Therefore, the IOException must be caught by the lambda itself. The recommended solutions1 are:

    • catch and handle it within the lambda, or
    • catch it in the lambda and rethrow it wrapped in an unchecked exception, then catch / handle the wrapped exception at the outer level. @Hank D's answer illustrates this.

    The problem with handling the IOException within the lambda is that the "for each" will continue running.


    1 - There is also the "sneaky throw" approach where you call a special method that subverts the Java rules and throws a checked exception without letting on. But it is "nasty", and I'm not sure it would directly help here. You would need to catch the IOException and sneakily rethrow it in the lambda.