java try finally block to close stream
Asked Answered
V

8

36

I want to close my stream in the finally block, but it throws an IOException so it seems like I have to nest another try block in my finally block in order to close the stream. Is that the right way to do it? It seems a bit clunky.

Here's the code:

 public void read() {
    try {
        r = new BufferedReader(new InputStreamReader(address.openStream()));
        String inLine;
        while ((inLine = r.readLine()) != null) {
            System.out.println(inLine);
        }
    } catch (IOException readException) {
        readException.printStackTrace();
    } finally {
        try {
            if (r!=null) r.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    }


}
Vermicular answered 28/8, 2011 at 23:17 Comment(1)
possible duplicate of Is there a preference for nested try/catch blocks?Belly
S
28

It seems a bit clunky.

It is. At least java7's try with resources fixes that.

Pre java7 you can make a closeStream function that swallows it:

public void closeStream(Closeable s){
    try{
        if(s!=null)s.close();
    }catch(IOException e){
        //Log or rethrow as unchecked (like RuntimException) ;)
    }
}

Or put the try...finally inside the try catch:

try{
    BufferedReader r = new BufferedReader(new InputStreamReader(address.openStream()));
    try{

        String inLine;
        while ((inLine = r.readLine()) != null) {
            System.out.println(inLine);
        }
    }finally{
        r.close();
    }
}catch(IOException e){
    e.printStackTrace();
}

It's more verbose and an exception in the finally will hide one in the try but it's semantically closer to the try-with-resources introduced in Java 7.

Saccharide answered 28/8, 2011 at 23:22 Comment(1)
I went with the second approach since its more cleaner and readable. This is really important as we want to avoid any memory leaks.Mechelle
P
36

Also if you're using Java 7, you can use a try-with-resources statement:

try(BufferedReader r = new BufferedReader(new InputStreamReader(address.openStream()))) {
    String inLine;
    while ((inLine = r.readLine()) != null) {
        System.out.println(inLine);
    }
} catch(IOException readException) {
    readException.printStackTrace();
}           
Pickax answered 28/8, 2011 at 23:56 Comment(2)
printing problem in stack-trace without logging it in is a problem, so instead that I suggest people to use log.debug(readException.getMessage());Korea
@Korea I don't see why that should be a problem. Logging paradigms has changed since 12 factors so logging to standard output is no more an issue. You log everything to stdout as you treat your process like a pipe and you can process your logs the way you want without touching your code.Chainplate
S
28

It seems a bit clunky.

It is. At least java7's try with resources fixes that.

Pre java7 you can make a closeStream function that swallows it:

public void closeStream(Closeable s){
    try{
        if(s!=null)s.close();
    }catch(IOException e){
        //Log or rethrow as unchecked (like RuntimException) ;)
    }
}

Or put the try...finally inside the try catch:

try{
    BufferedReader r = new BufferedReader(new InputStreamReader(address.openStream()));
    try{

        String inLine;
        while ((inLine = r.readLine()) != null) {
            System.out.println(inLine);
        }
    }finally{
        r.close();
    }
}catch(IOException e){
    e.printStackTrace();
}

It's more verbose and an exception in the finally will hide one in the try but it's semantically closer to the try-with-resources introduced in Java 7.

Saccharide answered 28/8, 2011 at 23:22 Comment(1)
I went with the second approach since its more cleaner and readable. This is really important as we want to avoid any memory leaks.Mechelle
C
23

In Java 7 you can do this...

try (BufferedReader r = new BufferedReader(...)){
     String inLine;
     while ((inLine = r.readLine()) != null) {
          System.out.println(inLine);
     }
} catch(IOException e) {
   //handle exception
}
  • Declaring a variable in the try block requires that it implements AutoCloseable.
  • Declaring a variable in the try block also limits its scope to the try block.
  • Any variable declared in the try block will automatically have close() called when the try block exits.

It's called a Try with resources statement.

Capo answered 28/8, 2011 at 23:57 Comment(0)
B
9

Yes it is clunky, ugly and confusing. One possible solution is to use Commons IO which offers a closeQuietly method.

There's a number of questions in the "Related" column on the right hand of this page that are actually duplicates, I advise to look through these for some other ways of dealing with this issue.

Bibbie answered 28/8, 2011 at 23:21 Comment(0)
H
6

Like the answer mentioning the Commons IO library, the Google Guava Libraries has a similar helper method for things which are java.io.Closeable. The class is com.google.common.io.Closeables. The function you are looking for is similarly named as Commons IO: closeQuietly().

Or you could roll your own to close a bunch like this: Closeables.close(closeable1, closeable2, closeable3, ...) :

import java.io.Closeable;
import java.util.HashMap;
import java.util.Map;

public class Closeables {
  public Map<Closeable, Exception> close(Closeable... closeables) {

  HashMap<Closeable, Exception> exceptions = null;

  for (Closeable closeable : closeables) {
    try {
      if(closeable != null) closeable.close();
    } catch (Exception e) {
        if (exceptions == null) {
          exceptions = new HashMap<Closeable, Exception>();
        }
        exceptions.put(closeable, e);
      }
    }

    return exceptions;
  }
}

And that even returns a map of any exceptions that were thrown or null if none were.

Heterodox answered 29/8, 2011 at 1:6 Comment(2)
To whomever down-voted my answer, could you please explain why so that I can learn from it?Heterodox
I'll upvote you so it balances out. Guava is a great librarySchutzstaffel
L
2

Your approach within finally is correct. If the code that you call in a finally block can possibly throw an exception, make sure that you either handle it, or log it. Never let it bubble out of the finally block.

Within the catch block you are swallowing the exception - which is not correct.

Thanks...

Lunde answered 28/8, 2011 at 23:34 Comment(0)
L
0
public void enumerateBar() throws SQLException {
    Statement statement = null;
    ResultSet resultSet = null;
    Connection connection = getConnection();
    try {
        statement = connection.createStatement();
        resultSet = statement.executeQuery("SELECT * FROM Bar");
        // Use resultSet
    }
    finally {
        try {
            if (resultSet != null)
                resultSet.close();
        }
        finally {
            try {
                if (statement != null)
                    statement.close();
            }
            finally {
                connection.close();
            }
        }
    }
}

private Connection getConnection() {
    return null;
}

source. This sample was useful for me.

Lockjaw answered 29/3, 2013 at 4:51 Comment(0)
K
0

First thing I noticed in your code is curly bracket { } missing from your code if you look at it. also you need to initialize value of r to null so you need to pass null value to object at first so that if condition you have written can do not null condition check and lets you close the stream.

Korea answered 21/2, 2019 at 3:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.