可选的异常捕获

时间:2013-08-08 17:15:23

标签: java exception-handling

是否可以设置一个可选的异常被捕获?

换句话说,一个例外可以:

  • 在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,这会使我的代码高度不可读。

如果这是不可能的(我怀疑它是),你会推荐什么替代/解决方案?

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

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

4 个答案:

答案 0 :(得分:3)

例外情况应该用于特殊情况。

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

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

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

这是你问题的答案,但不一定是个好主意。由于其他人会对评论进行双重评论,因此使用程序流程的例外情况并不理想。

答案 1 :(得分:2)

我对如何使用ThreadLocal感到有点模糊(并且很容易出现其他类似的问题),但是这样的话:

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(),并在最终范围的后期调用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子句,以保持编译器满意。这种机制不会消除对这些机制的需要。

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

答案 2 :(得分:0)

听起来你想要使用流量控制的异常,而不是报告真正特殊情况。

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

答案 3 :(得分:0)

您可以使用以下内容:

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

}catch (NullPointerException ex){
       killWindow();
}finally  {
    //to do something more.
}