为啥不建议用 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
(事实上,即使是没有任何控制结构的块也会创建一个。)
如果你仔细想想,它是有道理的:有些块是有条件的,比如定义 if
或 while
的主体的块。在上面的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置于循环内