Java 有一个try-catch块,您应该将所有语句都放在其中还是只放在不安全的语句中?

Java 有一个try-catch块,您应该将所有语句都放在其中还是只放在不安全的语句中?,java,exception-handling,Java,Exception Handling,假设save抛出并且i仅用于save。以下代码片段是否相同?请参阅符号学,性能< /强>等方面。 void bob(){ int i = calculate(); try { save(i); } catch(Exception e){ report(e) } } vs 通常我想知道的是,应该将函数的所有语句放在一个try catch块中,还是只放在抛出的语句中。它们是不同的。差异在于变量i的范围。在第二种情况下,不能在try catch块之外使用i 通常我想知

假设
save
抛出并且
i
仅用于
save
。以下代码片段是否相同?请参阅符号学,<强>性能< /强>等方面。

void bob(){
  int i = calculate();
  try {
    save(i);
  } catch(Exception e){
    report(e)
  }
}
vs


通常我想知道的是,应该将函数的所有语句放在一个
try catch
块中,还是只放在抛出的语句中。

它们是不同的。差异在于变量
i
的范围。在第二种情况下,不能在
try catch
块之外使用
i

通常我想知道,应该将函数的所有语句放在try-catch块中,还是只放在抛出的块中


更好的方法是将容易引发异常的代码包装在
try-catch
块中。这样,您可以处理与特定代码块相关的特定异常。因此,第1种方法是应该采用的方法。

语义方面,如果您已经决定了要将try-catch构造放在哪个方法中(并且您对正确做出该决定感到满意),那么答案相当简单:

  • 您应该在
    try
    中包含一个语句序列,这样,如果其中一个语句失败,则应放弃序列的其余部分。不多也不少
如果您正确地遵循上述建议,那么所需的程序流和最有效的局部变量范围等问题将很容易得到解决(在大多数情况下)。您会注意到,这并不排除嵌套
try
块的可能性

就性能而言,异常处理的开销在于实际抛出和捕获可丢弃对象。换句话说,只有在实际发生异常时才有真正的开销。代码中仅仅存在一个try-catch构造不会引入任何可测量的开销(可能根本没有)。此外,语句的数量(在给定的try-catch构造中)与其性能完全无关

编辑:我在JVM规范中找不到任何可链接的细节,但用户发布了许多帖子,检查和解释生成的字节码(以及其他许多帖子——谷歌搜索将产生一些有趣的结果)。在我看来,Java编译器似乎尽可能少地发出代码(当然,除了放入
try
catch
子句中的实际代码,以及一些不可避免的程序流指令,以跳过上述子句或弹出异常对象(如果有的话)。它让VM负责找出异常可能被捕获的位置。这很可能会将更多的负担转移到实际发生异常的场景中,但正如我们所知,异常是针对异常情况的,而不是控制流

<>我承认我不知道C++异常是如何实现的,但是从Java的角度来看,这是非常合理的,因为C++程序通常不在VM的帮助下运行。

< P> Rohit指出(正确地)变量 <代码>的范围在这里是不同的。 另一个区别是
calculate()
抛出未检查的异常;它将被
catch
块捕获。您是否应该在
try
块中调用
calculate()
,取决于您是要处理
catch
块中
calculate()
中未检查的异常,还是允许它向外抛出。在我看来,因为它是未选中的,因此完全出乎意料,所以我不会在
try
块中调用
calculate()

关于性能,我认为不应该有什么区别,因为性能影响是在遇到
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)
    }
}
在这种情况下:

void bob(){
  try {
    int i = calculate();
    save(i);
  } catch(Exception e){
    report(e)
  }
}
将捕获所有异常(错误除外),因为异常是所有类型的
异常
(错误除外)的超类。因此,不仅会处理选中的异常,还会处理未选中的异常,如
RuntimeException
。如果这是你的目标,那么我建议你这样做。
另一方面,我认为最小化try…catch块的范围是一个好的做法,因为在出现异常的情况下,定位有问题的代码行更容易。

性能如何?我知道一个
try-catch
会造成一些延迟,但它是否取决于包装块的大小?在分析代码并发现这是一个问题之前,不要担心这一点。我不会过早优化,我避免过早悲观;>@try-catch构造没有任何显著的开销。实际捕获异常的行为可能会带来您可能担心的开销。可能与您自己尝试查找的内容重复?请参阅我编辑的答案,我已经包含了一段关于性能问题的内容。回答很好,你是否有一些材料证明了
try-catch
的存在不会带来任何成本?因为在C++中简单地使用这个结构,改变了编译代码看起来在堆栈和堆上添加多个操作和元素的方式。我相信JLS指定了 Test/catch > /Cuth.Bug只在实际抛出异常时施加代价。如果某个方法失败,最好将该方法放在它自己的
try
块中,除非有问题的异常是check
void bob(){
  try {
    int i = calculate();
    save(i);
  } catch(Exception e){
    report(e)
  }
}