简体   繁体   中英

Java - Return statement and thrown exception using method inside catch block?

I have following code using hibernate to throw a custom exception on error and I also want to close the session in this case, since the exception won't be catched unless received on the client machine.

public <T> T get(final Session session, final String queryName) throws RemoteException
{
    final Query query = // query using given session ...

    try
    {
        return (T) query.uniqueResult();
    }
    catch (final HibernateException e)
    {
        SessionManager.logger.log(Level.SEVERE, "Could not retrieve Data", e);
        this.closeSession(session);
        throw new RemoteException("Could not retrieve Data");
    }
}

Now I have a helper method which closes the session and throws a given exception:

public void closeSessionAndThrow(final Session session, final RemoteException remoteException)
    throws RemoteException
{
    this.closeSession(session);
    throw remoteException;
}

Now I thought I could simplify my above code using:

public <T> T get(final Session session, final String queryName) throws RemoteException
{
    final Query query = // query using given session ...

    try
    {
        return (T) query.uniqueResult();
    }
    catch (final HibernateException e)
    {
        SessionManager.logger.log(Level.SEVERE, "Could not retrieve Data", e);
        this.closeSessionAndThrow(session, new RemoteException("Could not retrieve Data"));
    }
}

Now I need to add a return null; statement after the catch. Why?

Change the declaration of closeSessionAndThrow to return RemoteException and then "throw" the return result of calling it in your client code.

public RemoteException closeSessionAndThrow( ... )   // <-- add return type here
        throws RemoteException { ... }

public <T> T get( ... ) throws RemoteException
{
    try { ... }
    catch (final HibernateException e)
    {
        throw this.closeSessionAndThrow( ... );  // <-- add "throw" here
    }
}

This tricks the compiler into thinking it will always throw whatever exception is returned from closeSessionAndThrow . Since the helper method throws that exception itself, this second throw never comes into play. While you could return the exception from the helper, this invites error when someone forgets to add throw before the call.

This is the problem with methods like closeSessionAndThrow . The JLS rules do not allow the compiler to infer that since the method unconditionally throws an exception it can never return normally. The calling code therefore has to be written as if the method could return ... even though "we know" it cannot happen.

You simply have to go with the flow. This is an "unusual" control pattern that the Java language doesn't support as well as you / we would like.


(Under certain circumstances, one can prove that the method will always throw an exception under certain assumptions. However, since the method is public and in a different class, one of the assumptions is that the classes that define and use the method won't be changed and compiled independently of each other. Of course, that is not the kind of assumption that a compiler can make ... and it partly explains why the JLS rules don't attempt to cover this pattern.

If they were to "fix" this problem, it would require something like an annotation, or change to the java syntax to declare that the helper method cannot return.)

While closeSessionAndThrow always throws the remote exception, the compiler doesn't dive into the method to find that out, therefore the compiler only knows that it COULD throw a RemoteException, not that it WILL. I would maybe do something like this:

public RemoteException closeSessionAndThrow(final Session session, final Exception e, String msg)
{
    SessionManager.logger.log(Level.SEVERE, msg, e);
    this.closeSession(session);
    return new RemoteException(msg);
}

public <T> T get(final Session session, final String queryName) throws RemoteException
{
    final Query query = // query using given session ...

    try
    {
        return (T) query.uniqueResult();
    }
    catch (final HibernateException e)
    {
        throw this.closeSessionAndThrow(session, e, "Could not retrieve Data");
    }
}

Since this method must return something, you should put a return null; after

this.closeSessionAndThrow(session, new RemoteException("Could not retrieve Data"));

but still within the catch clause or use a finally clause.

Why do you need to do this? Because your function must return something. and since one it returns from:

this.closeSessionAndThrow(session, new RemoteException("Could not retrieve Data"));

and doesn't return anything, this causes a compiler error.

add finally to try-catch block finally { return null; } - If execution goes into try block and result is success it would return, so finally would never get executed. - If execution goes into catch block, the finally block gets executed after catch and would return null. Safe execution!

Not correct answer!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM