Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136082

What is the correct way to silently close InputStream in finally block without losing the original exception?

I am wondering if the below code closes InputStream in finally block correctly

InputStream is = new FileInputStream("test");
try {
    for(;;) {
        int b = is.read();
        ...
    }
} finally {
    try {
        is.close();
    } catch(IOException e) {
    }
}

If an exception happens during is.read() will be it ignored / suppressed if an exception happens during is.close()?

Upvotes: 31

Views: 33241

Answers (9)

Igor Vuković
Igor Vuković

Reputation: 764

You can close it with IOUtils from https://commons.apache.org/proper/commons-io/

public void readStream(InputStream ins) {
    try {
        //do some operation with stream         
    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        IOUtils.closeQuietly(ins);
    }
}

Upvotes: 15

Dhiraj Himani
Dhiraj Himani

Reputation: 1102

This is the sample to help to understand your problem, if you declare the scanner in the try-catch block it will give compiler warning the resource is not closed. so either make it locally or just in try()

import java.util.InputMismatchException;
import java.util.Scanner;

class ScanInt {
public static void main(String[] args) {
    System.out.println("Type an integer in the console: ");

    try (Scanner consoleScanner = new Scanner(System.in);) {
        System.out.println("You typed the integer value: "
                + consoleScanner.nextInt());

    } catch (InputMismatchException | ArrayIndexOutOfBoundsException exception) {
        System.out.println("Catch Bowled");
        exception.printStackTrace();

    }
    System.out.println("----------------");
}
}

Upvotes: 0

flup
flup

Reputation: 27103

The Java 6 specs say

If execution of the try block completes abruptly for any other reason R, then the finally block is executed. Then there is a choice: If the finally block completes normally, then the try statement completes abruptly for reason R. If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).

So you are right, you will lose the original exception.

The solution probably is to write your finally block so defensively that it is a bigger surprise (worth propagating) if the finally block fails than if an exception comes out of the try catch block.

So, for example, if it is possible that the stream may be null when you try to close it, check it:

InputStream is = new FileInputStream("test");
try {
    for(;;) {
        int b = is.read();
        ...
    }
} finally {
    try {
        if( is!=null ) {
            is.close();
        }
    } catch(IOException e) {
    }
}

In Java 7, Alpedar's solution is the way to go of course.

Upvotes: 8

Alpedar
Alpedar

Reputation: 1344

Best way is to use Java 7 and use try with resources, or do same thing manualy and add exception from closing as suppressed exception.

Pre Java 7: If you are throwing your custom exception, you can add in it supressed exception like it is done in Java 7 (in your exception create fields List suppressed and put there exceptions from close operation and when dealing with your exception, look there too. If you cannot do that, I don't know anything better than just log it.

examples: from Java tutorials

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

but better form is:

static String readFirstLineFromFile(String path) throws IOException {
    try (FileReader fr = new FileReader(path);
         BufferedReader br = new BufferedReader(fr)) {
        return br.readLine();
    }
}

This way even if creation of FileReader is succesfull but creation of BufferedReader fails (eg not enough memory), FileReader will be closed.

Upvotes: 17

user207421
user207421

Reputation: 311018

If an exception happens during is.read() will be it ignored / suppressed if an exception happens during is.close()?

Yes. You have a catch block for the exception in close() which does not re-throw the exception. Ergo it is not propagated or rethrown.

Upvotes: 0

android developer
android developer

Reputation: 116000

How about the next solution:

InputStream is = new FileInputStream("test");
Exception foundException=null;
try {
    for(;;) {
        int b = is.read();
        ...
    }
} catch (Exception e){
  foundException=e;
}
finally {
    if(is!=null)
    try {
        is.close();
    } catch(IOException e) {
    }
}
//handle foundException here if needed

Upvotes: 0

Étienne Miret
Étienne Miret

Reputation: 6660

With the code you posted:

  • If is.close() throws an IOException, it gets discarded and the original exception propagates.
  • If is.close() throws something else (a RuntimeException or an Error), it propagates and the original exception is discarded.

With Java 7, the correct way to close an InputStream without loosing the original exception is to use a try-with-resources statement:

try (InputStream is = new FileInputStream("test")) {
    for(;;) {
        int b = is.read();
        // ...
    }
}

Prior to Java 7, what you do is just fine, except you may want to catch all exceptions instead of just IOExceptions.

Upvotes: 2

Sean Landsman
Sean Landsman

Reputation: 7177

Based on your code sample if an exception occurs at the int b = is.read(); point, then the exception will be raised higher up the call chain.

Note though that the finally block will still execute and if the Inputstream invalid another exception will be thrown, but this exception will be "swallowed", which may be acceptable depending on your use case.

Edit:

Based on the title of your question, I would add that what you have is fine in my opinion. You may want to additionally add a catch block to explicitly handle (or perhaps wrap) any exception within the first try block, but it is also acceptable to let any IO exceptions raise up - this really depends on your API. It may or may not be acceptable to let IO exceptions raise up. If it is, then what you have it fine - if it isn't then you may want to handle/wrap the IO exception with something more suitable to your program.

Upvotes: 1

sksamuel
sksamuel

Reputation: 16387

The exception from is.close() will be suppressed and the exception from is.read() will be the one that propagates up.

Upvotes: 3

Related Questions