To be honest, having implemented compilers and interpretters, the "for"
and "while" loop examples that they provide seem entirely logical. The
cases, in fact, are similar to saying "this statement is false", and Java
would have to specify specific behavior for these cases.

I still find it very difficult to believe that the close() method is
not called for no reason other than being in a finally block. However,
I wonder if it might be related to the "finalizer thread" issue that
is raised on the page you cite.

tim.

> This site demonstrates the pitfalls with using returns & finally:
> 
> http://www.cs.arizona.edu/sumatra/hallofshame/
> 
> It seems like this behaviour is not specified by the Java Language 
> Specification.
> 
> Cheers,
> Scott
> 
> Greg Davis wrote:
> > This deals with try/catch blocks and finallys. I always believed that "no
> > matter what" a finally block is always called.  While this seems to remain
> > true, it does not seem to necessarily properly call the code within the
> > block.  In the section below I have some code and explanation of how a
> > finally gets called, but does not execute the code within.
> > 
> > There seems to be an issue with closing a JDBC connection if a method
> > returns in the middle of the try/catch block.  It seems to call the finally,
> > but does not close the connection.  It does seem to call static methods like
> > System.out.println() perfectly fine.  I don't know if it being static has
> > anything to do with it.  I haven't researched it too far since it was really
> > hard to find.  First off you have to have a Factory like a ConnectionPool
> > that spawns out inscances of an object for other classes to use. Then it
> > must need to have the user close it's connection at some point so the
> > Factory can control resources. The only example I really have on hand is a
> > JDBC connection pool in a J2EE app server.  This is where the problem occurd
> > for us.  If the methods "returns" are moved outside the try/catch block, the
> > Connection.close() happens properly and the ConnectionPool does not
> > complain.
> > 
> > I realize the getColumnClose() is the better way to implement the code
> > ayway, but I wanted to show everyone this problem in case they accidentally
> > do it in their code somewhere.  Any returns in the try or catches seemed to
> > make the finally not be properly executed. I seem to remember some wierd
> > rule about this at JavaOne last year, but my head is still racing from all
> > that information. :-)
> > 
> > Any comments?
> > 
> > package test;
> > 
> > import java.sql.*;
> > import javax.sql.DataSource;
> > import javax.naming.*;
> > 
> > /**
> >  * <p>Title: TryCatchTest</p>
> >  * <p>Description: This is a test application for try/catch problem.  If
> > using
> >  * a Connection Pool in JDBC and you try to "return" a value within a
> > try/catch
> >  * that is inside a method, the finally of that try/catch is not completely
> > run.
> >  * It seems to go through the finally(I.E. Sytem.out.println() works, but
> > the
> >  * Connection.close() is either never called or not executed.  If the
> > "return"
> >  * is moved to the outside of the catch block, the connection is properly
> > closed.
> >  * <br>
> >  * We found this because a J2EE server which had a connection pool was
> > telling
> >  * us we were not closing our connections.  I dn't know if there is some
> > rule that
> >  * when a "return" has been called only static methods or something like
> > that can
> >  * be called.</p>
> >  * <p>Copyright: Copyright (c) 2002</p>
> >  * <p>Company: Western Electronics </p>
> >  * @author <a href="mail:[EMAIL PROTECTED]">Greg Davis</a>
> >  * @version 1.0
> >  */
> > 
> > public class TryCatchTest
> > {
> >   Context jndiContext;
> > 
> >   public TryCatchTest()
> >   {
> >     try
> >     {
> >       jndiContext = new InitialContext();
> >     }
> >     catch(NamingException ne)
> >     {}
> >   }
> > 
> >   public String getColumnNoClose()
> >   {
> >     Connection conn = null;
> >     PreparedStatement ps = null;
> >     ResultSet rs = null;
> >     try
> >     {
> >       String sql ="SELECT table_name FROM sequence";
> >       conn
> > =((DataSource)jndiContext.lookup("jdbc/mySourceDS")).getConnection();
> >       ps = conn.prepareStatement(sql);
> >       rs = ps.executeQuery();
> >       if(rs != null && rs.next())
> >       {
> >         //This return causes the ?non-static? code within the finally to not
> > to be run.
> >         return rs.getString("table_name");
> >       }
> >       //same here, the finally ?non-static? code is not called.
> >       return null;
> >     }
> >     catch(NamingException ne)
> >     {
> >       //same here, the finally ?non-static? code is not called.
> >       return null;
> >     }
> >     catch(SQLException sqle)
> >     {
> >       sqle.printStackTrace();
> >       //The same problem occurs here.  The finally ?non-static? code is not
> > called
> >       return null;
> >     }
> >     finally
> >     {
> >       //This system out works, but the conn.close() does not.  The only way
> > I
> >       //know how to check this is to create a ConnectionPool yourself that
> > watches
> >       //the connections it spawns out, or user a pre-built one that does the
> > same.
> >       //We use Orion 1.5.4 J2EE App server (free for development). if you
> > want
> >       //to test this out.
> >       System.out.println("Finally called in noClose()");
> >       try
> >       {
> >         if(rs != null)
> >           rs.close();
> >         if(ps != null)
> >           ps.close();
> >         if(conn != null)
> >           conn.close();
> >       }
> >       catch(SQLException sqle)
> >       {
> >         sqle.printStackTrace();
> >       }
> >     }
> >   }
> > 
> >   public String getColumnClose()
> >   {
> >     String returnValue = null;
> >     Connection conn = null;
> >     PreparedStatement ps = null;
> >     ResultSet rs = null;
> >     try
> >     {
> >       String sql ="SELECT table_name FROM sequence";
> >       conn
> > =((DataSource)jndiContext.lookup("jdbc/mySourceDS")).getConnection();
> >       ps = conn.prepareStatement(sql);
> >       rs = ps.executeQuery();
> >       if(rs != null && rs.next())
> >       {
> >         //This does call the finally
> >         returnValue = rs.getString("table_name");
> >       }
> > 
> >     }
> >     catch(NamingException ne)
> >     {}
> >     catch(SQLException sqle)
> >     {
> >       //This allso calles the finally if I break the quey
> >       sqle.printStackTrace();
> >     }
> >     finally
> >     {
> >       //This one works normally
> >       System.out.println("Finally called in Close()");
> >       try
> >       {
> >         if(rs != null)
> >           rs.close();
> >         if(ps != null)
> >           ps.close();
> >         if(conn != null)
> >           conn.close();
> >       }
> >       catch(SQLException sqle)
> >       {
> >         sqle.printStackTrace();
> >       }
> >     }
> >     return returnValue;
> >   }
> > 
> >   public static void main(String[] args)
> >   {
> >     TryCatchTest tct1 = new TryCatchTest();
> >     System.out.println("tct1.getColumnNoClose():" +
> > tct1.getColumnNoClose());
> >     System.out.println("tct1.getColumnClose():" +tct1.getColumnClose());
> >   }
> > }
> > 
> > 


Reply via email to