如何处理在try-catch

时间:2015-08-04 08:49:38

标签: java exception exception-handling

考虑以下场景:我有一个对象池,I(1)借用该对象池,(2)对该对象执行某些操作,然后(3)必须将其返回到池中。挑战在于前两个步骤可能会抛出已检查的异常,步骤(1)甚至会抛出一个简单的Exception

让我向您展示我目前使用的代码:

MyObject objectFromPool = null;
try {
    objectFromPool = pool.borrowObject(); // step (1), throws plain Exception   
    objectFromPool.doSomething();         // step (2), throws FailedToDoSomethingException
} catch (FailedToDoSomethingException e) {
    throw new MyCustomRuntimeException(e);    
} catch (Exception e) {
    // Now what? Did objectFromPool.doSomething() throw this exception or pool.borrowObject()?
} finally {
    if (objectFromPool != null) {
        pool.returnObject(objectFromPool); // step (3)
    }
}

如何处理普通Exception的任何建议?我不希望这段代码抛出一个已检查的异常,因为调用者无论如何都不知道如何处理它。但我仍然希望区分pool.borrowObject()objectFromPool.doSomething()的例外,因为前者表示“技术”例外而后者表示“业务”问题。

注意:我既不控制pool.borrowObject()也不控制objectFromPool.doSomething()的代码。两者都来自外部库,我不知道他们可能抛出什么样的RuntimeException

5 个答案:

答案 0 :(得分:1)

如果您想知道哪个方法调用引发了异常,请从每个方法中抛出不同的异常。

根据您的评论,doSomething似乎只会引发FailedToDoSomethingException。如果这是真的,那么到达第二个捕获区块(catch (Exception e))的唯一方法是pool.borrowObject()投掷Exception

如果两个方法调用都抛出不是Exception的{​​{1}},则必须具有更多特定的catch块,以便以不同方式处理由不同方法抛出的异常。如果要抛出基类FailedToDoSomethingException类的实例,则应考虑抛出更具体的自定义异常类实例。

答案 1 :(得分:1)

我认为更好的方法是将可疑的Exception封装到一个特定的异常中,该异常将落入最终的catch中并最终:

    MyObject objectFromPool = null;
    try {
        try {
                objectFromPool = pool.borrowObject(); // step (1), throws plain Exception   
            } catch (Exception e) {
                // Encapsulate into an specific exception type:
                throw new MyOwnException(e);
            }
            objectFromPool.doSomething();         // step (2), throws FailedToDoSomethingException
        } catch (FailedToDoSomethingException e) {
            throw new MyCustomRuntimeException(e);    
        } catch (MyOwnException e) {
            ...
        } finally {
            if (objectFromPool != null) {
                pool.returnObject(objectFromPool); // step (3)
            }
        }

通过这种方式,您可以保留原始捕获并最终保留算法,毫不怀疑每个异常的来源。

还有一件事:请记住,Exception甚至可能是RuntimeException。您是否也有兴趣捕获RuntimeExceptions?如果没有,请添加一个额外的捕获来让它们传播:

        try {
                objectFromPool = pool.borrowObject(); // step (1), throws plain Exception   
            } catch (RuntimeException e) {
                // Let it propagate:
                throw e;
            } catch (Exception e) {
                // Encapsulate into an specific exception type:
                throw new MyOwnException(e);
            }

答案 2 :(得分:0)

如果两种方法都抛出普通Exception,你可以通过将第二种方法包装到新的try / catch块来区分它们:

try {
    objectFromPool = pool.borrowObject(); 
    try {
        objectFromPool.doSomething();
    } catch (Exception ex){
        // do something
    }  
} catch (Exception e) {
    // pool.borrowObject() throw this e
} finally ...

但如果objectFromPool.doSomething()只能投出FailedToDoSomethingException,请按照 Eran 的回答

答案 3 :(得分:0)

怎么样:

MyObject objectFromPool = null;
try{
    try {
        objectFromPool = pool.borrowObject(); // step (1), throws plain Exception   
    } catch (Exception e) {
        // pool.borrowObject has thrown exception
    }
    try {
        objectFromPool.doSomething();         // step (2), throws FailedToDoSomethingException
    } catch (FailedToDoSomethingException e) {
        throw new MyCustomRuntimeException(e);    
    }  

} finally {
return pool.returnObject(objectFromPool); // step (3)
}

(按照您的提及编辑,您希望始终pool.returnObject(objectFromPool);

另一种方法是为每个单独的try-catch块而不是这个总体try-finally块创建一个finally块。

答案 4 :(得分:0)

您无法更改所调用方法的代码,并且它们都可以抛出普通Exception。好的新功能是你可以通过堆栈跟踪来区分哪种方法抛出了异常:

MyObject objectFromPool = null;
try {
  objectFromPool = pool.borrowObject();
  objectFromPool.doSomething();
} catch (FailedToDoSomethingException e) {
  throw new MyCustomRuntimeException(e);    
} catch (Exception e) {
  //here we get the method name from the first element in the stack trace
  //this way we can identify the method that actually threw our exception
  if(e.getStackTrace()[0].getMethodName().equals("borrowObject")) {
    //pool.borrowObject threw the exception
  } else if (e.getStackTrace()[0].getMethodName().equals("doSomething")) {
    //objectFromPool.doSomething() threw the exception
  }
} finally {
  if (objectFromPool != null) {
    pool.returnObject(objectFromPool);
  }
}

您甚至可以通过比较堆栈跟踪中的getClassName()来扩展它。

请记住,在重构的情况下,这可能会出错。如果您更改其中一个方法的名称,if子句可能会失败,以防您忘记在此更改名称。