假设save
抛出,i
仅用于save
。以下代码片段是否相同?请考虑语义,性能等方面。
void bob(){
int i = calculate();
try {
save(i);
} catch(Exception e){
report(e)
}
}
VS
void bob(){
try {
int i = calculate();
save(i);
} catch(Exception e){
report(e)
}
}
一般来说,我想知道,如果将一个函数的所有语句放在try-catch
块中,或者只放置一个函数。
答案 0 :(得分:11)
语义明智,如果你已经决定将你的try-catch结构放入哪种方法(并且你觉得你已经正确地做出了这个决定),那么答案很简单:
try
块中包含一系列语句,以便在其中一个语句失败时,应该放弃序列的其余部分。没有更多也没有更少的陈述。如果您正确地遵循上述建议,那么很容易且很明显地解决诸如所需程序流和局部变量的最有效范围之类的问题(在大多数情况下)。您会注意到这并不排除嵌套try
块的可能性。
性能方面,异常处理的开销在于实际抛出和捕获throwable对象。换句话说,只有在实际发生异常时才会出现。。代码中仅存在try-catch构造不会引入任何可测量的开销(可能根本没有)。此外,语句的数量(在给定的try-catch构造内)与其性能完全无关。
编辑:我找不到要链接到的JVM规范中的任何细节,但是有很多用户检查和解释生成的字节码,like this one和{{ 3}}(在许多其他人中 - 谷歌搜索将产生一些有趣的结果)。对我来说,看起来Java编译器尝试尽可能少地发出(当然,除了您在try
和catch
子句中添加的实际代码以及一些不可避免的程序流指令跳转所述子句或弹出异常对象,如果有的话)。它留给VM负责找出异常被捕获的位置。这很可能会给实际发生异常的情况带来更多负担,但是,正如我们所知,异常是针对特殊情况,而不是控制流。
我承认我不知道C ++异常通常是如何实现的,但考虑到C ++程序通常不会在VM的帮助下运行,因此它们与Java完全不同是非常合理的。
答案 1 :(得分:5)
他们不一样。不同之处在于变量i
的范围。在第二种情况下,您无法在i
块之外使用try-catch
。
一般来说,我想知道,如果一个函数的所有语句都放在try-catch块中,或者只是抛出一个函数。
更好的方法是将代码容易包装在try-catch
块中抛出异常。这样,您就可以处理与特定代码块相关的特定异常。所以,第一种方式是最适合的方式。
答案 2 :(得分:2)
在这种情况下:
void bob(){
try {
int i = calculate();
save(i);
} catch(Exception e){
report(e)
}
}
将捕获所有异常(错误除外),因为异常是所有Exception
的超类(错误除外)。因此,不仅可以处理已检查的异常,还可以取消选中,例如RuntimeException
。如果这是你的目标,那么我建议采用这种方式。
另一方面,我认为最小化try...catch
块的范围是一种很好的做法,因为如果找到有问题的代码行的例外更容易。
答案 3 :(得分:1)
Rohit指出(正确地)变量i
的范围在这里是不同的。
另外一个区别是如果calculate()
抛出未经检查的异常;它将被catch
块捕获。是否应将calculate()
块中的try
调用取决于您是否要在calculate()
块中catch
处理未经检查的异常,或允许其向外扔。在我看来,由于它是未经检查的,因此完全出乎意料,我不会在calculate()
块中调用try
。
关于性能,我认为应该没有区别,因为性能命中是遇到try
块,并且在这两种情况下只有一个块。如果你在每行周围有单独的try-catch
块,那么性能可能会降低,但可能没有你曾经注意到的任何方式:
// degraded performance example
void bob(){
int i;
try {
i = calculate();
} catch(Exception e){
report(e)
}
try {
save(i);
} catch(Exception e){
report(e)
}
}