2012-12-22 85 views
13

这可能是一个广泛的问题,不太适合SO风格,但如果可能的话,我仍然希望得到一些提示或指导。使用嵌套异常是一种很好的做法吗?

我一直在寻找一些遗留代码,发现它的一部分有异常嵌套3或4级别的方法。
这被认为是一种正常的做法,或者应该尽可能避免这种代码风格?如果应该避免,除了异常处理的成本增加和可读性降低之外,还有什么负面影响?有没有常见的重构代码的方法来避免这种情况?

回答

16

我个人更喜欢下面的意识形态

裹外国人例外

“异类”异常是由Java API或第三方库抛出的异常。换句话说,你不能控制的异常。

它更好地捕获所有外来异常并将它们包装在适当的应用程序特定异常中。一旦外来异常转换为您自己的异常,您可以以任何喜欢的方式传播异常。

重新抛出检查异常会导致混乱

如果应用程序使用checked异常,重新抛出原来的异常意味着重新抛出它的方法也必须申报。

越接近调用层次顶部,越多的异常将被声明抛出。除非你只是声明所有的方法来抛出异常。但是,如果你这样做了,你不妨使用未经检查的异常,因为你真的从编译器异常检查中获益无论如何。

这就是为什么我喜欢捕获的非专用例外,敷在他们的应用程序特定的异常,传播他们调用堆栈之前。

包装指南:发生异常的上下文可能与异常本身的位置一样重要。应用程序中的给定位置可以通过不同的执行路径到达,如果发生错误,则执行路径可能会影响错误的严重程度和原因。

如果您需要在将异常信息传播到调用堆栈时将异常信息添加到异常中,则需要使用主动传播。换句话说,您需要在调用堆栈的各个相关位置捕获异常,并在重新展开或打包之前向其添加相关上下文信息。

public void doSomething() throws SomeException{ 

    try{ 

     doSomethingThatCanThrowException(); 

    } catch (SomeException e){ 

     e.addContextInformation(“more info”); 
     throw e; //throw e, or wrap it – see next line. 

     //throw new WrappingException(e, “more information”); 

    } finally { 
     //clean up – close open resources etc. 
    } 

} 
0

您应该废除异常嵌套。您应该首先避免链接异常,或者(选择性地)解包,然后再将嵌套异常重新引入堆栈。

0

关于处理遗留代码,我建议你看看这本书涵盖的话题: http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052 你甚至不必须贯穿整本书,看看这关你此刻的事情。

另外,关于良好做法一本好书是: http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=sr_1_1?s=books&ie=UTF8&qid=1356340809&sr=1-1&keywords=clean+code

当处理嵌套异常被重构代码,并使用运行时,而不是checked异常,并处理那些需要的最好的办法。这样代码更易读,更易于维护。

0

它依赖于业务逻辑。您可以对其本身的例外采取行动,或者您可以一直传播给呼叫方,并将其留给呼叫方以进行他想要的操作。

例如有许多第三方API不处理异常,但是它们将其从方法中抛弃,因此便于API用户根据需要采取行动。

e.q. oracle JDBC驱动程序。 Driver.getConnection()抛出异常。现在,呼叫者/ API用户可以根据他们的需要来处理它。可以打印堆栈跟踪,可以通知管理员询问他的注意,或者可以选择只是静静地退出应用程序。

2

检查异常不应该传播到堆栈或链接如果可能。如果一个方法抛出一个checked异常,它的调用者应该处理它,如果调用者没有处理它并将它传播给它的调用者,那么整体复杂度就会增加。

在三层例如:道,服务,控制器

DAO层将抛出DAOException 服务层不应该暴露DAOException到控制器,而是应该抛出相关BuinessExceptions,该控制器应处理。

3

异常处理通常是一种处理流量控制的昂贵方式(当然对于C#和Java)。

当构造一个异常对象时,运行时会做很多工作 - 将堆栈跟踪结合在一起,找出异常处理的位置等等。

如果流控制语句被用于流量控制,所有这些都会花费在内存和CPU资源上,这些资源不需要扩展。

此外,还有一个语义问题。例外情况适用于特殊情况,不适用于正常流量控制。应该使用异常处理来处理意外/异常情况,而不是正常的程序流程,否则,未捕获的异常会告诉你更少的情况。

除了这两个,还有别人读代码的问题。以这种方式使用异常并不是大多数程序员期望的,所以可读性和代码的可理解性受到影响。当人们看到“例外”时,人们会认为 - 发生了一些不好的事情,而这些事情不应该正常发生。所以,以这种方式使用异常很简单。

请看看下面的链接

Exception Handling: Common Problems and Best Practice with Java 1.4 - pdf

Why not use exceptions as regular flow of control?

Best Practices for Exception Handling

Error Handling

Mr. Google Links

0

有两种方法:

To generate a separate exception for each event. 
To create a generic exception and describe what caused it 

第一种方法可以让你编写不同的代码来处理不同的事件,但它需要你去写大量的异常类,并在某些情况下,它可能太多了。

第二种方法更简洁,但它使处理不同情况变得困难。

在编程中经常发生这种情况,最好的解决方案就是在中间平衡生成单独的异常并在其他情况下使用一个异常。

在这种情况下,拇指的规则可能是针对您要专门用单独代码处理的异常生成单独的Exception类。

类似于扔什么,我们也应该有什么赶控制。我们可以用我们的catch块两种方法:

所有单个catch块。例如:

catch (Throwable e) { 
throw new CommandExecutorException(e); 
} 

许多捕获块各有一个例外。例如:

} catch (ClassCastException e1) { 
... 
} catch (FileNotFoundException e) { 
... 
} catch (IOException e) { 
... 
} 

第一种方法是非常紧凑的,但基本上组在同一案件中每一个例外,它只有在所有的例外同样的管理和做同样的事情的情况是非常有用的。 这种方法一般不提倡,因为它提供了对异常没有控制被逮住,有时会导致错误强硬,这也很难找到。

第二种方法需要更多的代码行,但您可以根据发生的异常执行不同的操作。这种方法更灵活,但是在某些情况下会导致你的方法会很长,由于异常处理。

3

我一直在寻找一些遗留代码,发现它的一部分有异常嵌套3或4级别的方法。

这是否被认为是一种常规做法,或者应该尽可能避免这种代码风格?

这不是一个以这种方式处理异常的必要过程,因为它会增加您的应用程序开销,直到您确实需要处理非常特定的异常(checked或异常异常),并且可以忽略开销以获得特定信息来处理这个异常。

如果应该避免,除了增加异常处理成本和降低可读性外,还有什么负面影响?

正如我所提到的,如果您不打算使用嵌套异常处理(向上层处理程序添加一些附加信息时抛出),您将不会获取有关异常的特定信息,您可能/一些强硬异常,但在嵌套的情况下,你可以通过处理特定情况下做动作。

有没有常见的方法来重构代码以避免这种情况?

如果你有一个算不上很好的程序,做你想做的事情,没有严重的错误,为了上帝的缘故,不要管它!当你需要修复一个bug或添加一个功能时,你可以毫不犹豫地重构你在努力中遇到的代码。覆盖自定义异常处理程序中的异常类并添加一些添加的功能来处理您的问题。

重写方法不能抛出比重写方法声明的更新或更广泛的已检查异常。例如,声明FileNotFoundException的方法不能由声明SQLException,Exception或任何其他非运行时异常的方法覆盖,除非它是FileNotFoundException的子类。

跳这将帮助你。

相关问题