0

是否可以进行可选捕获的异常?

换句话说,一个异常可以:

  • 被捕获在一个 try-catch 块中
  • 如果不存在 try-catch 块,则跳过

为了形象化,我有一个ReportedException,它只是 的一个普通子类RuntimeException,并且希望能够在需要时捕获它:

try
{
    hideWindow();
}
catch (ReportedException ex)
{
    // Window could not be hidden.
    // Exception has already been caught and logged by parseInput(),
    // and now we're going to do something more.

    printAdditionalErrorMessage();
}

注意:我编辑了上面的示例以更好地适应我的问题。

如果结果不相关,则跳过捕获:

hideWindow(); // We don't care if there was an error or not.
openAnotherWindow();

我知道我可以将 catch 块留空并拥有与上面相同的内容,但我ReportedException经常使用它,这会使我的代码高度不可读。

如果不可能(我怀疑是),您会推荐什么替代方案/绕行?

PS 示例中使用的方法名称只是 foo 和 bar 的。

编辑:我知道我不需要捕捉 RuntimeExceptions。我想要的是在它们发生时忽略它们。

4

4 回答 4

3

异常应该用于异常情况。

从您的示例中,如果未隐藏的窗口是典型事件,则不应引发异常。如果那是您的函数,则使用返回值来指示它是否成功,而不是抛出异常。然后,当您不关心它是否成功时,您可以放心地忽略返回值。

如果您无法控制该方法,则可以将其包装在另一个捕获异常并将其转换为返回值的方法中。例如

private boolean tryHideWindow() {
    try {
        hideWindow();
    }
    catch (ReportedException ex) {
        return false;
    }
    return true;
}

如果您需要异常的一些参数来确定要做什么,那么您可以改为返回异常。

private static class MyReturnType {
    private final Throwable thrown;
    private final OrigRtnType returnVal;
    public MyReturnType(Throwable thrown) {
        this.thrown = thrown;
        this.returnVal = null;
    }
    public MyReturnType(OrigRtnType returnVal) {
        this.thrown = null;
        this.returnVal = returnVal
    }
    public boolean wasExceptionThrown() {
        return thrown != null;
    }
}

private MyReturnType tryHideWindow() {
    try {
        OrigRtnType returnVal = hideWindow();
    }
    catch (ReportedException ex) {
        return new MyReturnType(ex);
    }
    return new MyReturnType(returnVal);
}

这是对您问题的回答,但这不一定是一个好主意。由于其他人会加倍评论,因此对程序流使用异常并不理想。

于 2013-08-08T17:23:04.860 回答
2

我对如何使用 ThreadLocal 有点模糊(而且还有其他一些 tupos),但是像这样:

public class IgnorableException {  

     static class DontIgnoreCount  {
         int count;
     }

     // Thread local variable containing each thread's ID
     private static final ThreadLocal<DontIgnoreCount> dontIgnoreCount =
         new ThreadLocal<DontIgnoreCount>();

     static void incrementDontIgnore() {
         DontIgnoreCount counter = dontIgnoreCount.get();
         if (counter == null) {
             counter = new DontIgnoreCount();
             dontIgnoreCount.set(counter);
         }
         counter.count++;
     }

     static void decrementDontIgnore() {
         DontIgnoreCount counter = dontIgnoreCount.get();
         // Must not be null here
         counter.count--;

     static bool shouldSignal() {
         DontIgnoreCount counter = dontIgnoreCount.get();
         return counter.count > 0;
     }
}

要使用,请在 try 范围的早期调用 DontIgnoreCount.incrementIgnoreCount(),并在 finally 范围的后期调用 DontIgnoreCount.decrementIgnoreCount()。

当发出遵循此协议的异常信号时,仅在 shouldSignal 返回 true 时才发出信号。

void iWannaCatchException() {
    try {
        IgnornableException.incrementDontIgnore();
        int x = someOptionallySignallingMethod();
    }
    catch (...) {
        ...
    }
    finally {
        IgnorableException.decrementDontIgnore();
    }
}

void iDontWannaCatchException() {
    int x = someOptionallySignallingMethod();
}

int someOptionallySignallingMethod() {
    if (somethingBad) {
        if (IgnorableException.shouldSignal()) {
            throw new BadException();
        }
    }
    return 42;
}

请注意,上面没有显示throws您必须添加以使编译器满意的任何子句。这种机制不会消除对这些的需求。

您还可以实现一个委托/观察者方案,用一堆观察者对象替换简单的计数器,并将消息传递给观察者而不是抛出异常。但这本身(没有耦合的异常/尝试范围)不允许将堆栈吹到适当的恢复点。

于 2013-08-08T18:21:53.073 回答
0

听起来您想将异常用于流量控制,而不是报告真正的异常情况。

通常不赞成使用异常进行流量控制。常见的方法是返回成功/失败指示作为函数的返回值。

于 2013-08-08T17:19:58.913 回答
0

你可以使用这样的东西:

try{
    hideWindow();
}catch (ReportedException ex){
    // ingore

}catch (NullPointerException ex){
       killWindow();
}finally  {
    //to do something more.
}
于 2013-08-08T17:29:51.847 回答