【问题标题】:Why does a method require return statement in catch even though catch is re-throwing exception为什么一个方法在 catch 中需要 return 语句,即使 catch 是重新抛出异常
【发布时间】:2016-06-10 20:42:01
【问题描述】:

我写了一个方法,它在 try 语句中返回一些值。在 catch 内部,我调用了 handleException,它将具有理解异常并重新抛出新异常的转换逻辑。这里的handleException 总是抛出异常,getXYZ() 仍然给出编译时错误,期望返回语句。我没有处理异常,我只是抛出新的异常,那么为什么该方法需要返回语句。

public String getXYZ(String input) {
    try {
        return getFromDAO(input);
    } catch (Exception e) {
        handleException(e);
    }
}
private void handleException(Exception e) {
    try {
        throw e;
    } catch(SomeException se) {
        throw new MyRuntimeException("MyException message", se);
    } catch(SomeOtherException soe) {
        throw new MyRuntimeException("MyException message", soe);
    }
}

此方法的其他版本编译。

public String getXYZ(String input) {
    try {
        return getFromDAO(input);
    } catch (Exception e) {
        throw e;
    }
}

【问题讨论】:

  • 另外,您可能希望在方法参数中添加一些 throws 子句。 See here for an example 稍后它将帮助您确保您尝试捕获这些 Exception 对象

标签: java exception-handling


【解决方案1】:

你没有在catch 块中抛出任何东西,你正在调用你的句柄函数,这最终会导致一个新的异常被抛出,但getXYZ 中的实际代码正在@987654323 中进行函数调用@。如果您将handleException 更改为以后在某些情况下不抛出异常,那getXYZ 会返回什么?

【讨论】:

  • handleException方法的正确使用方法是什么?它应该返回异常对象而不是抛出它然后 getXYZ 抛出那个异常吗?
  • 为什么不把那些catch 块放在getXYZ 中而不需要一个handle 函数来从一种异常类型转换为另一种异常类型?
  • 我必须在一个类的许多方法中捕获相同的异常,所以我正在编写一个单独的私有方法来进行异常转换。
  • 如果这一切都来自getFromDAO,你能创建一个包装函数来抛出正确类型的异常吗?
  • 其他方法可能不会调用getFromDAO。对于每种这样的方法,我都必须编写一个包装器。
【解决方案2】:

解决此问题的一种方法是让编译器清楚您希望抛出异常。

public String getXYZ(String input) {
    try {
        return getFromDAO(input);
    } catch (Exception e) {
        throw handleException(e); // compiles ok.
    }
}

private RuntimeException handleException(Exception e) {
    try {
        throw e;
    } catch(SomeException se) {
        return new MyRuntimeException("MyException message", se);
    } catch(SomeOtherException soe) {
        return new MyRuntimeException("MyException message", soe);
    } catch(RuntimeException re) {
        return re;
    } catch(Exception e2) {
        return new MyRuntimeException("MyException message", e2);
    }
}

顺便说一句,另一种方法是根本不包装异常并保留异常。

public String getXYZ(String input) {
    try {
        return getFromDAO(input);
    } catch (Exception e) {
        throw rethrow(e); // compiles ok.
    }
}

/**
 * Cast a CheckedException as an unchecked one.
 *
 * @param throwable to cast
 * @param <T>       the type of the Throwable
 * @return this method will never return a Throwable instance, it will just throw it.
 * @throws T the throwable as an unchecked throwable
 */
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
    throw (T) throwable; // rely on vacuous cast
}

【讨论】:

  • 如果您想将检查的异常转换为运行时异常,您需要添加另一个 catch 子句以使代码编译...
【解决方案3】:

您可能还想考虑使用新的 java 8 lambda 功能来解决您的问题。您必须创建一个函数式接口来声明 lambda 的签名(有相关例外)。您的 handleException 方法现在将成为运行 lambda 并处理异常的方法。

public String getXYZ(String input) {
    return handleKnownExceptions(() -> getFromDAO(input));
}

private <T> T handleKnownExceptions(ThrowingCode<T> throwingCode)
{
    try {
        return throwingCode.get();
    } catch(SomeException se) {
        throw new MyRuntimeException("MyException message", se);
    } catch(SomeOtherException soe) {
        throw new MyRuntimeException("MyException message", soe);
    }
}

@FunctionalInterface
public interface ThrowingCode<T>
{
    T get() throws SomeException, SomeOtherException;
}

【讨论】:

    【解决方案4】:

    有一种我见过几次的模式来处理这种情况。你让handleException 方法声明它返回一个异常。这只是指示性的,它永远不会返回任何东西,它总是会抛出,就像以前一样。声明的返回类型将允许调用者使用throw handleException() 语句,这将使编译器满意。结果代码将是:

    public String getXYZ(String input) throws Exception {
        try {
            return getFromDAO(input);
        } catch (Exception e) {
            throw handleException(e);
        }
    }
    
    /**
     * This method will never return normally, always throws. 
     */
    private Exception handleException(Exception e) throws Exception
    {
        try {
            throw e;
        } catch(SomeException se) {
            throw new MyRuntimeException("MyException message", se);
        } catch(SomeOtherException soe) {
            throw new MyRuntimeException("MyException message", soe);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-19
      • 2014-06-19
      • 2015-12-19
      • 1970-01-01
      • 2019-03-02
      • 2012-06-27
      • 2013-10-16
      • 1970-01-01
      • 2021-09-09
      相关资源
      最近更新 更多