为啥不建议用 try catch

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为啥不建议用 try catch相关的知识,希望对你有一定的参考价值。

不同语言处理Try Catch的机制不一样,所以也会有不同回答。

比如C++,是不推荐用try catch的,它推荐使用Windows API那种HResult来返回错误情况,原因是try catch会在已有的代码上面增加额外的cost, 这个额外的cost不是说只有throw exception的时候才会有,而是在try catch block里面的每一行代码中都会有,这也是为什么他不建议你使用try catch最主要的原因。在Windows的源代码中,是没有任何try catch的,全部用HResult来处理。
比如C#, try catch是建议使用的,C#设计的时候吸取的C++ try catch的教训,所以直接用Try catch包裹已有代码增加的cost可以忽略不计,但是如果真的在代码运行过程中throw exception了,这个cost还是很大的。所以,在C#代码设计中,throw exception基本上是你认为不会发生这种意外的情况下,否则,如果是常见错误,最好不要throw exception。
比如Java, try catch也是建议使用的,我这个用的不熟,不过看它的说明,即使是throw exception的时候的cost也很小。
总结说来,try catch是否建议使用要看具体语言,最重要衡量的标准就是它对已有的代码性能有多大的影响。但是从它设计的角度就是为了处理一些意料不到的情况,但是因为当初引入的时候各种各样的原因,导致有些语言为了性能,不推荐使用。
BTW, try catch最好不要catch (Exception), 这样会吃掉不该吃的问题,比如C#中的StackOverflowException, OutOfMemoryException, NullReferenceException etc. 该crash的时候就应该让App crash, restart, 这也是保护你service的一个好方法。
希望对你有帮助~
参考技术A try to do sth

为啥 Try/Catch 块会创建新的变量范围?

【中文标题】为啥 Try/Catch 块会创建新的变量范围?【英文标题】:Why does a Try/Catch block create new variable scope?为什么 Try/Catch 块会创建新的变量范围? 【发布时间】:2012-07-24 04:43:30 【问题描述】:

例如:

try

    SomeObject someObject = new SomeObject();
    someObject.dangerousMethod();

catch(Exception e)


someObject.anotherMethod(); //can't access someObject!

但是你可以在 try/catch 块之前声明它,然后它就可以正常工作了:

SomeObject someObject;
try

    someObject = new SomeObject();
    someObject.dangerousMethod();

catch(Exception e)


someObject.anotherMethod(); //works fine

我只是想知道这样做的设计原因。为什么在 try/catch 块内创建的对象不在方法其余部分的范围内?也许我并没有深入了解try/catch 的工作原理,除了只关注Exceptions 抛出。

【问题讨论】:

Java 中的每个块都定义了一个新的范围。不只是尝试块。不遵循一般规则将是非常不一致的。 【参考方案1】:

为什么在 try/catch 块中创建的对象不在方法其余部分的范围内?

他们是。 try/catch 块中声明的变量不在包含块的范围内,原因与所有其他变量声明在它们出现的范围内都是本地的一样:这就是规范定义它的方式。 :-)(更多内容如下,包括对您评论的回复。)

这是一个在try/catch创建的对象,可在其外部访问:

SomeObject someObject = null;
try

    someObject = new SomeObject();
    someObject.dangerousMethod();

catch(Exception e)


someObject.anotherMethod(); // This is fine -- unless the SomeObject
                            // constructor threw the exception, in which
                            // case someObject will be null

注意区别。 变量在哪里声明定义了它存在的范围,而不是对象在哪里创建。 p>

但是根据上面的方法名称等,更有用的结构是:

SomeObject someObject = new SomeObject();
try

    someObject.dangerousMethod();

catch(Exception e)


someObject.anotherMethod();

你的评论:

我想我对为什么还要为 try/catch 块创建另一个作用域感到困惑。

在 Java 中,所有块都创建范围。 if 的主体、else 的主体、while 的主体等等——它们都创建了一个新的嵌套变量范围:

if (foo) 
    SomeObject bar = new SomeObject();

bar.doSomething(); // <== Compilation error, `bar` is not defined

(事实上,即使是没有任何控制结构的块也会创建一个。)

如果你仔细想想,它是有道理的:有些块是有条件的,比如定义 ifwhile 的主体的块。在上面的if 中,bar 可能已声明也可能未声明(取决于foo 的值),这毫无意义,因为编译器当然没有foo 的运行时值的概念。所以可能是为了一致性,Java 的设计者使用 all 块创建一个新的嵌套范围。 (JavaScript 的设计者走了另一条路——根本没有块作用域,尽管它正在被添加——而且这种方法让人们感到困惑。)

【讨论】:

打败我!这个范围是为了防止抛出异常(即使在被声明的对象的构造函数中)。如果尝试从未到达该实例化语句,我们将无法继续使用该对象。 我想我很困惑为什么还要为 try/catch 块创建另一个作用域。 我想他知道它是如何工作的;相反,他在问为什么决定这样做。 @Atlos:因为在 Java 中,所有块都创建范围。 if 的主体、else 的主体、while 的主体等等。它们都创建了自己的变量范围。这就是语言的定义方式。它的优点是您可以在更接近使用它们的位置声明事物;它的缺点是这样做会导致您编写长函数,而实际上您应该将它们分解为子函数。 :-) @T.J.Crowder 这比保持所有块一致更有意义。如果我想让它从抛出异常的方法中分配一个值,然后在其他地方使用它,我发现必须在块之外声明所有变量是很乏味的。估计没有办法解决。【参考方案2】:

在 Java 中,只要有 对,就可以创建一个新范围。

考虑以下

class ScopeTest 
    public static void main(String[] args) 
        int i = 0;
         int j = 0; System.out.println(j); 
         int j = 2; System.out.println(j); 
    

try/catch 只是遵循这个习惯用法,并强制创建 对。

要回应您对非括号 if 语句的跟进,请考虑:

class MultiRTree 
    public static void main(String...args) 
        boolean b = args.length == 0;
        if(b) String s = new String("hello");
    

结果

c:\files\j>javac ScopeTest.java
ScopeTest.java:4: not a statement
        if(b) String s = new String("hello");
              ^
ScopeTest.java:4: ';' expected
        if(b) String s = new String("hello");
                    ^
2 errors

但是,这将编译得很好。

class ScopeTest 
    public static void main(String...args) 
        boolean b = args.length == 0;
        if(b) new String("hello");
    

为什么会这样,根据 JLS 第 14 章第 9 节,如果定义为:

IfThenStatement:
    if ( Expression ) Statement

而语句定义为(14.5)

Statement:
    StatementWithoutTrailingSubstatement
    LabeledStatement
    IfThenStatement
    IfThenElseStatement
    WhileStatement
    ForStatement

StatementWithoutTrailingSubstatement:
    Block
    EmptyStatement
    ExpressionStatement
    AssertStatement
    SwitchStatement
    DoStatement
    BreakStatement
    ContinueStatement
    ReturnStatement
    SynchronizedStatement
    ThrowStatement
    TryStatement

因此,块、表达式语句或空语句都可以。但是声明(在第 6 章中定义)不在语句的语法中。

【讨论】:

如果你有一个if 语句单行语句,但你没有使用 对呢?比如if(true) SomeObject someObject = new SomeObject()someObject 会在方法的范围内还是编译器会为我插入隐含的括号? @Atlos - 它做了一些尴尬的事情。只能说,不允许!我会编辑它。 基本上,new SomeObject(); 是允许的,因为它是一个声明,但 SomeObject so = new SomeObject() 是不允许的,因为它是一个声明(即使它包含一个声明)。【参考方案3】:

变量或对象的范围在定义它的范围内(由大括号 定义)。

由于 try catch 启动了一个新的范围,其中可能会引发一些错误,因此在 try catch 中定义的对象在其范围之外不可用。

【讨论】:

【参考方案4】:

每次你使用方括号“”时,你都在用 C++ 和 Java 表达一个新的作用域。您尝试尝试某个操作需要一些内部设置,并且限定名称允许快速跳出 try 块而无需进行大量清理。

只要不存在名称冲突(如在 Python 中),某些语言将允许您访问范围之外的那些范围变量,但这需要稍微不同的内部堆栈结构,并且仍然可能增加尝试的成本无论如何都要抓住。

这也是 Java 中定义范围定义的方式——正如许多其他答案所指出的那样。

【讨论】:

【参考方案5】:

try/catch 创建一个新作用域的原因很简单,因为它是一个块级元素。事实上,简单地将 随机放置在一个方法中会创建一个具有自己本地范围的新代码块。

【讨论】:

以上是关于为啥不建议用 try catch的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 NSError 间接参数而不是 @try/@catch/@finally

用powershell的try catch, 为啥try里面出现异常,catch 捕获不到呢?

Powershell错误处理,try catch finally

编写高质量代码改善C#程序的157个建议——建议64:为循环增加Tester-Doer模式而不是将try-catch置于循环内

try语句可以套try语句?

何时使用 try/catch 块?