【问题标题】:Java - Return statement and thrown exception using method inside catch block?Java - 使用 catch 块内的方法返回语句和抛出异常?
【发布时间】:2012-06-27 06:57:21
【问题描述】:

我有以下代码使用 hibernate 在错误时引发自定义异常,并且在这种情况下我还想关闭会话,因为除非在客户端计算机上接收到异常,否则不会捕获该异常。

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");
    }
}

现在我有一个辅助方法可以关闭会话并抛出给定的异常:

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

现在我想我可以使用以下代码来简化上面的代码:

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"));
    }
}

现在我需要在 catch 之后添加一个 return null; 语句。为什么?

【问题讨论】:

    标签: java exception return


    【解决方案1】:

    closeSessionAndThrow的声明更改为返回RemoteException,然后在您的客户端代码中“抛出”调用它的返回结果。

    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
        }
    }
    

    这会诱使编译器认为它总是会抛出从closeSessionAndThrow 返回的任何异常。由于辅助方法本身会引发该异常,因此第二个 throw 永远不会发挥作用。虽然您可以从帮助程序返回异常,但当有人忘记在调用前添加 throw 时,这会引发错误。

    【讨论】:

    • 感谢您的回答。是的,我忘记了该方法不能保证抛出该异常!,编译器应该如何知道这一点。
    【解决方案2】:

    这是closeSessionAndThrow 等方法的问题。 JLS 规则不允许编译器推断,由于该方法无条件地抛出异常,因此它永远无法正常返回。因此,调用代码必须像方法可以返回一样编写......即使“我们知道”它不会发生。

    您只需顺其自然。这是一种“不寻常”的控制模式,Java 语言并不像您/我们希望的那样支持。


    (在某些情况下,可以证明该方法在某些假设下总是会抛出异常。但是,由于该方法是public并且在不同的类中,因此假设之一是定义和使用的类该方法不会相互独立地更改和编译。当然,这不是编译器可以做出的那种假设……它部分解释了为什么 JLS 规则不试图涵盖这种模式。

    如果他们要“修复”这个问题,则需要注释之类的东西,或者更改为 java 语法来声明辅助方法无法返回。)

    【讨论】:

    • 但我最喜欢提供的答案。它有保证,我还可以删除我仍然必须以其他方法关闭会话的 finally 块(将会话移动到 try 块),从而减少了一些代码。
    • 是的......它巧妙地回避了这个问题。但是,它并不适用于所有情况。例如,假设您的辅助方法返回FileNotFoundExceptionInterruptedException;即两个不相关的检查异常。现在调用方法必须声明为 throwing Exception。糟糕,糟糕,糟糕。
    • @StephenC - 这是支持未检查异常的另一个原因。
    • @DavidHarkness - 如果您使用抛出标准异常的标准 Java API,这将无济于事。让我们坚持现实...
    • @StephenC - 虽然示例使用RemoteException,但问题本身是通用的。在编写自定义辅助方法时,选择异常类型几乎没有超出现实范围。
    【解决方案3】:

    虽然 closeSessionAndThrow 总是抛出远程异常,但编译器不会深入研究方法来找出它,因此编译器只知道它可以抛出 RemoteException,而不是它会抛出。我可能会做这样的事情:

    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");
        }
    }
    

    【讨论】:

      【解决方案4】:

      由于这个方法必须返回一些东西,你应该在后面加上一个return null;

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

      但仍在catch 子句内或使用finally 子句。

      为什么需要这样做?因为你的函数必须返回一些东西。并且因为它从以下位置返回:

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

      并且不返回任何内容,这会导致编译器错误。

      【讨论】:

        【解决方案5】:

        最后添加到 try-catch 块 最后 { 返回空值; } - 如果执行进入 try 块并且结果是成功它会返回,所以 finally 永远不会被执行。 - 如果执行进入 catch 块,则 finally 块在 catch 之后执行并返回 null。安全执行!

        答案不正确!

        【讨论】:

        • 最后总是被执行,即使是在 return 语句中。 stackoverflow.com/questions/65035/…
        • 哎呀——这将导致代码始终返回 null,即使在没有抛出或捕获异常的情况下也是如此。这不是问题所需要的。
        • Returning from finally 总是一个坏主意。谷歌搜索该短语,然后删除或修改答案:)
        • 我的错!我现在明白了。谢谢!
        猜你喜欢
        • 1970-01-01
        • 2012-09-21
        • 1970-01-01
        • 2013-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-19
        • 1970-01-01
        相关资源
        最近更新 更多