Is a finally block without a catch block a java anti-pattern?

前端 未结 12 631
鱼传尺愫
鱼传尺愫 2020-12-05 12:35

I just had a pretty painful troubleshooting experience in troubleshooting some code that looked like this:

try {
   doSomeStuff()
   doMore()
} finally {
            


        
相关标签:
12条回答
  • 2020-12-05 13:13

    try-finally may help you to reduce copy-paste code in case a method has multiple return statements. Consider the following example (Android Java):

    boolean doSomethingIfTableNotEmpty(SQLiteDatabase db) {
        Cursor cursor = db.rawQuery("SELECT * FROM table", null);
        if (cursor != null) { 
            try {
                if (cursor.getCount() == 0) { 
                    return false;
                }
            } finally {
                // this will get executed even if return was executed above
                cursor.close();
            }
        }
        // database had rows, so do something...
        return true;
    }
    

    If there was no finally clause, you might have to write cursor.close() twice: just before return false and also after the surrounding if clause.

    0 讨论(0)
  • 2020-12-05 13:14

    In my opinion, it's more the case that finally with a catch indicate some kind of problem. The resource idiom is very simple:

    acquire
    try {
        use
    } finally {
        release
    }
    

    In Java you can have an exception from pretty much anywhere. Often the acquire throws a checked exception, the sensible way to handle that is to put a catch around the how lot. Don't try some hideous null checking.

    If you were going to be really anal you should note that there are implied priorities among exceptions. For instance ThreadDeath should clobber all, whether it comes from acquire/use/release. Handling these priorities correctly is unsightly.

    Therefore, abstract your resource handling away with the Execute Around idiom.

    0 讨论(0)
  • 2020-12-05 13:15

    Not at all.

    What's wrong is the code inside the finally.

    Remember that finally will always get executed, and is just risky ( as you have just witnessed ) to put something that may throw an exception there.

    0 讨论(0)
  • 2020-12-05 13:22

    I'd say a try block without a catch block is an anti-pattern. Saying "Don't have a finally without a catch" is a subset of "Don't have a try without a catch".

    0 讨论(0)
  • 2020-12-05 13:25

    I think it's far from being an anti-pattern and is something I do very frequently when it's critical do deallocate resources obtained during the method execution.

    One thing I do when dealing with file handles (for writing) is flushing the stream before closing it using the IOUtils.closeQuietly method, which doesn't throw exceptions:

    
    OutputStream os = null;
    OutputStreamWriter wos = null;
    try { 
       os = new FileOutputStream(...);
       wos = new OutputStreamWriter(os);
       // Lots of code
    
       wos.flush();
       os.flush();
    finally {
       IOUtils.closeQuietly(wos);
       IOUtils.closeQuietly(os);
    }
    
    

    I like doing it that way for the following reasons:

    • It's not completely safe to ignore an exception when closing a file - if there are bytes that were not written to the file yet, then the file may not be in the state the caller would expect;
    • So, if an exception is raised during the flush() method, it will be propagated to the caller but I still will make sure all the files are closed. The method IOUtils.closeQuietly(...) is less verbose then the corresponding try ... catch ... ignore me block;
    • If using multiple output streams the order for the flush() method is important. The streams that were created by passing other streams as constructors should be flushed first. The same thing is valid for the close() method, but the flush() is more clear in my opinion.
    0 讨论(0)
  • 2020-12-05 13:25

    I use try/finally in the following form :

    try{
       Connection connection = ConnectionManager.openConnection();
       try{
           //work with the connection;
       }finally{
           if(connection != null){
              connection.close();           
           }
       }
    }catch(ConnectionException connectionException){
       //handle connection exception;
    }
    

    I prefer this to the try/catch/finally (+ nested try/catch in the finally). I think that it is more concise and I don't duplicate the catch(Exception).

    0 讨论(0)
提交回复
热议问题