http://www.bitscn.com/pdb/java/200605/23824.html
本章的第一个例子是: if(t == null) throw new NullPointerException(); 看起来似乎在传递进入一个方法的每个句柄中都必须检查null(因为不知道调用者是否已传递了一个有效的句柄),这无疑是相当可怕的。但幸运的是,我们根本不必这样做——它属于Java进行的标准运行期检查的一部分。若对一个空句柄发出了调用,Java会自动产生一个NullPointerException违例。所以上述代码在任何情况下都是多余的。 这个类别里含有一系列违例类型。它们全部由Java自动生成,毋需我们亲自动手把它们包含到自己的违例规范里。最方便的是,通过将它们置入单独一个名为RuntimeException的基础类下面,它们全部组合到一起。这是一个很好的继承例子:它建立了一系列具有某种共通性的类型,都具有某些共通的特征与行为。此外,我们没必要专门写一个违例规范,指出一个方法可能会“掷”出一个RuntimeException,因为已经假定可能出现那种情况。由于它们用于指出编程中的错误,所以几乎永远不必专门捕获一个“运行期违例”——RuntimeException——它在默认情况下会自动得到处理。若必须检查RuntimeException,我们的代码就会变得相当繁复。在我们自己的包里,可选择“掷”出一部分RuntimeException。 如果不捕获这些违例,又会出现什么情况呢?由于编译器并不强制违例规范捕获它们,所以假如不捕获的话,一个RuntimeException可能过滤掉我们到达main()方法的所有途径。为体会此时发生的事情,请试试下面这个例子: //: NeverCaught.java // Ignoring RuntimeExceptions public class NeverCaught { static void f() { throw new RuntimeException("From f()"); } static void g() { f(); } public static void main(String[] args) { g(); } } ///:~ 大家已经看到,一个RuntimeException(或者从它继承的任何东西)属于一种特殊情况,因为编译器不要求为这些类型指定违例规范。 输出如下: java.lang.RuntimeException: From f() at NeverCaught.f(NeverCaught.java:9) at NeverCaught.g(NeverCaught.java:12) at NeverCaught.main(NeverCaught.java:15) 所以答案就是:假若一个RuntimeException获得到达main()的所有途径,同时不被捕获,那么当程序退出时,会为那个违例调用printStackTrace()。 注意也许能在自己的代码中仅忽略RuntimeException,因为编译器已正确实行了其他所有控制。因为RuntimeException在此时代表一个编程错误: (1) 一个我们不能捕获的错误(例如,由客户程序员接收传递给自己方法的一个空句柄)。 (2) 作为一名程序员,一个应在自己的代码中检查的错误(如ArrayIndexOutOfBoundException,此时应注意数组的大小)。 可以看出,最好的做法是在这种情况下违例,因为它们有助于程序的调试。 另外一个有趣的地方是,我们不可将Java违例划分为单一用途的工具。的确,它们设计用于控制那些讨厌的运行期错误——由代码控制范围之外的其他力量产生。但是,它也特别有助于调试某些特殊类型的编程错误,那些是编译器侦测不到的。
http://bbs.chinaunix.net/thread-1239870-9-1.html
原帖由
lgfang 于 2008-8-31 03:30 发表
》》我认为使用try/catch的难度在于上层函数捕捉到了异常也不知道该怎么办。比如下层函数抛出了一个NullReferenceException,上层函数能做什么?
上层不知道,就不捕捉,继续上传。总有知道的。如果都不知道 ...
》》我认为使用try/catch的难度在于上层函数捕捉到了异常也不知道该怎么办。比如下层函数抛出了一个NullReferenceException,上层函数能做什么? >>上层不知道,就不捕捉,继续上传。总有知道的。如果都不知道,那么程序崩溃也没什么可说的。 通常情况是越往上传就越不知道,最终到了UI层,只能笼统的catch() { printf("Unknow Error. Please contact system administrator."); } 》》使用try/catch的难度还在于,如何保证上层函数捕捉到了异常之后“会”进行处理。使用exception的软件里面,基本上都难以避免catch() thow;或者catch() {/*do nothing*/}这样的语句。 >>每个模块只负责管好自己。比方说你提供一个API负责转换字符串到整数,你的API不可能去管负责接收输入的模块怎么工作。如果你接收到错误输入抛出后,那个模块没管,那是它不好。不能因为它不处理这种错误你的API就不抛异常(你根本不知道怎么办的情况下,不抛异常你又能做什么呢?) 允许模块抛出异常,实际上就是允许模块“不管好自己”。“接收到错误输入抛出后,那个模块没管”,通常是因为那个模块也不知道该怎么管,或者它压根就不想管只是throw然后推卸责任:你看这不是我的问题,是下层抛的异常。
<
<
<
有个签名貌似帖子好看一点
>
>
>
帖子
1133
主题
42
精华
0
可用积分
7395
专家积分
10
在线时间
768 小时
注册时间
2005-03-03
最后登录
2013-04-10
论坛徽章:
0
原帖由
lgfang 于 2008-8-31 03:32 发表
请不要断章取义:
当前context知道如何如何处理就处理了,不清楚的话才抛出异常让知道怎么处理这种情况的模块去处理。
那请你举个当前context不知道如何处理的情况出来吧。 某个模块知道自己“哪些情况不知道如何处理”,这是个悖谬。 更通常的情况是,这个模块把一切它没考虑到的事情都throw出去了,把它不愿去考虑的事情也throw出去了。然后外层调用开始头痛。 [ 本帖最后由 wwwsq 于 2008-8-31 03:55 编辑 ]
<
<
<
有个签名貌似帖子好看一点
>
>
>
伦理协会顾问调研员
帖子
879
主题
14
精华
0
可用积分
2386
专家积分
10
在线时间
118 小时
注册时间
2008-04-12
最后登录
2010-06-18
论坛徽章:
0
原帖由
wwwsq 于 2008-8-31 03:52 发表
那请你举个当前context不知道如何处理的情况出来吧。
某个模块知道自己“哪些情况不知道如何处理”,这是个悖谬。
更通常的情况是,这个模块把一切它没考虑到的事情都throw出去了,把它不愿去考虑的 ...
很受用啊 两位继续辩论 这种高质量的辩论绝对欢迎
hello, world!
帖子
3347
主题
255
精华
2
可用积分
17554
专家积分
40
在线时间
3576 小时
注册时间
2005-09-14
最后登录
2014-03-21
论坛徽章:
1
原帖由
wwwsq 于 2008-8-31 01:32 发表
你这话说了等于没说。
机制和原则当然不是"确保正确处理"的前提也不是唯一方法,但合理的机制和原则是保证软件质量的最好方法。
规矩有很多,有好的有烂的。烂规矩确实多半会导致烂代码,但是没有规矩几 ...
我就奇了怪了, 不说那么远, try catch 怎么就隐藏了错误呢。 不过一种机制而已, 和返回值一样, 除了倾向于 用try catch捕捉异常而不是正常的错误外, 又有什么区别呢(性能暂放一边) 至于不讲规矩几乎一定导致烂代码, 我倒不这么认为. 正所谓讲规矩未必产生高质量代码一样, 不讲规矩也未必就是很差. 至少我不认为我的代码质量比周围人差, 或许我周围的人都非常差或者我有眼不识泰山吧
授我以鱼, 不要授我以渔
找工作, linux 系统编程, 服务器编程 30K 左右
帖子
3347
主题
255
精华
2
可用积分
17554
专家积分
40
在线时间
3576 小时
注册时间
2005-09-14
最后登录
2014-03-21
论坛徽章:
1
原帖由
wwwsq 于 2008-8-31 03:01 发表
我认为使用try/catch的难度在于上层函数捕捉到了异常也不知道该怎么办。比如下层函数抛出了一个NullReferenceException,上层函数能做什么?
使用try/catch的难度还在于,如何保证上层函数捕捉到了异常之后“ ...
这个是有道理的, 一个函数以返回值而不是异常提供给其他函数, 我非常赞同 不过函数内部我可以用异常阿, 本函数抛出的异常本函数解决, 还是在减少代码量与清晰度上有好处的。 至于内部实现而不是公共接口, 在不严重影响清晰度的情况下, 函数抛出异常我也不认为有什么大不了, 到底好处多还是坏处多, 具体问题具体分析, 见仁见智而已
授我以鱼, 不要授我以渔
找工作, linux 系统编程, 服务器编程 30K 左右
帖子
624
主题
42
精华
0
可用积分
1364
专家积分
15
在线时间
109 小时
注册时间
2006-09-01
最后登录
2014-02-02
论坛徽章:
0
那请你举个当前context不知道如何处理的情况出来吧。
try/catch 和 返回值在这个层面上来讲,不过是两种传递错误的方式。难道你的函数从来不返回错误值么?返回错误值后从来就不处理么?
某个模块知道自己“哪些情况不知道如何处理”,这是个悖谬。
不知道你是从来没写过代码,还是没有认真思考。
更通常的情况是,这个模块把一切它没考虑到的事情都throw出去了,把它不愿去考虑的事情也throw出去了。然后外层调用开始头痛。
exception 是你throw的,没考虑到,你怎么throw?唯一的问题是下层throw出来的、应该在本层catch的异常可能会由于疏忽或不知道而没有捕捉。这就是我说的c++中异常的问题之一:无法保证上层函数捕捉所有应该捕捉的异常。这方面感觉java的机制更好。但是就这方面而言,在C/C++里采用返回值的方式传递错误并不比抛异常要好,实际上更糟糕(见下面的例子)。
通常情况是越往上传就越不知道,最终到了UI层,只能笼统的catch() { printf("Unknow Error. Please contact system administrator."); }
用你的逻辑,采用函数返回值的方式同样有这问题?实际上所谓“越往上传就越不知道”那是因为已经传过头了。还是那句话,这就是我说的c++中异常的问题之一:无法保证上层函数捕捉所有应该捕捉的异常。 假设这样一个程序:函数 fa 对于输入的每一条记录调用 fb 进行处理。fb又调fc,fc调fd。在fd中遇到错误,没法处理。fc也不知道,但是fb知道。来对比一下用exception和返回值两种方式吧:
fa(){ for (a tuple in set) { try { fb(); } catch (Ex1) { //error handle } catch (Ex2) { // error handle } catch (...) { warning_and_log; // 程序员知道这个应用不能崩溃,所以处理完想到的所有异常后, // 加了这个block作为“防御”。万一真的走到这一步的话,顶多 // 某一条记录处理失败,不影响其它其它记录的处理。 } } } fb() { try { fc(); } catch { // error handling and then go on } // other operation } fc() { fd(); } fd() { if (error) { throw ex; } }
复制代码
1,理想情况下,异常由fd=>fc=>fb后,在fb中处理。 2,如果fb中忘了捕捉(我说的难点:没有机制保证fb一定回捕捉fd抛出的异常),由于fa中的预防措施,错误的影响被限制在一条记录以内,而且这个错误被记录下来。从site把数据取回后,通过重现和调试找到bug。 3,如果fa也没捕捉,exception一路往上,最终导致程序崩溃。在错误发生后,公司赔客户一大笔钱,然后由core文件很快找到bug。 再来看看用返回值的情况:
fa(){ for (a tuple in set) { switch (fb()) { case 1: //error handle break; case 2: // error handle break; default: warning_and_log; } } } fb() { if (! fc()) { // error handling and then go on } // other operation } fc() { if ( ! fd()) { return false; } else { return true; } } fd() { if (error) { return false; } else { return true; } }
复制代码
1,理想情况,错误仍然是 fd=>fc=>fb,然后在fb中处理。和采用exception没有区别,但是代码更难看些。 2,如果fb中忘了检查返回值,程序的错误就被隐藏下来 3,如果fa中忘了,错误同样也被隐藏下 4,还有在fc中也可能忘了。 错误被隐藏的后果,最好的情况是错误导致在后续的操作过程中崩溃。于是公司赔客户一大笔钱,然后去找bug。由于错误暴露的地方并非它发生的地方,找bug有可能要多花更多功夫。 更倒霉的情况是,系统静悄悄的继续运行下去。直到有一天终端用户投诉到客户那里。客户大为恼火,索赔更大 一笔钱。因为没有错误日志,甚至连有多少条错误记录还得的费一番周折才能统计出来。另外,除了和上面一样找bug要多费些功夫外,还得再花额外的功夫去更正之前的错误。
这个是有道理的, 一个函数以返回值而不是异常提供给其他函数, 我非常赞同
除了上面说的,返回值还有个问题:有时候返回值不方便。比如说构造函数。再举一例:如何定义函数 str2int? 一个自然的想法就是 int str2int(const string& str)。可是如果这样的话,返回值就无法表示错误了(就像atoi)。于是只能改成 int str2int(const string& str, int& output)。定义成这样的话,用起来就不方便了。例如 try { ret = str2int("120") + str2int("119");}catch (){} 就得写成: int a,b,rc; if ( (c = str2int("120", &a)) && (c = str2int("119", &b))) { ret = a + b; } else { } 最后,说明一点,我并不是想说c++的异常机制很完美,或者说用异常才是“正确的”,不用是错误的。据说关于C++异常机制的争论很多,有些项目就禁用异常。它们应该自有其道理,我也很希望有真正比较了解c++异常的人士出来剖析一下异常的缺陷。我只是想说本帖的那些反对异常的理由在我看来不成立。 [ 本帖最后由 lgfang 于 2008-9-2 21:18 编辑 ]
帖子
1133
主题
42
精华
0
可用积分
7395
专家积分
10
在线时间
768 小时
注册时间
2005-03-03
最后登录
2013-04-10
论坛徽章:
0
原帖由
zylthinking 于 2008-8-31 23:08 发表
我就奇了怪了, 不说那么远, try catch 怎么就隐藏了错误呢。
不过一种机制而已, 和返回值一样, 除了倾向于用try catch捕捉异常而不是正常的错误外, 又有什么区别呢(性能暂放一边)
至于不讲规矩几乎一定导 ...
返回值是显式的、静态的,异常是隐式的、易变的。 我们这边有个规则,函数有返回值的那么调用者必须检查返回值。如果不知道返回值的含义,那么就查文档、查代码、问人。这个规则简单清晰,职责分明,很容易做到。 异常则是隐式的,而且易变的,缺乏清晰描述的。比如,一个函数int do_something(string s)本来可能会抛出十种异常(这十种异常各代表什么业务含义通常是没有文档说明的),上层函数随便猜测了这些异常代表的业务含义,东拼西凑之后总算通过了测试;在某次修改之后,这个函数变成可能会抛出十二种异常,上层调用怎么办?于是catch() throw;这样的代码就开始泛滥,一个exception可以从最底层抛到最顶层。 前面有位仁兄举了个例子,说有些非关键操作失败了要继续下面的关键步骤,这种事情要我来考虑到话,我会用一个socket connection往另外的进程发数据,让其他单独的进程来做非关键操作,既然是非关键操作就不要和关键操作混在一个进程里。 [ 本帖最后由 wwwsq 于 2008-9-3 17:10 编辑 ]
<
<
<
有个签名貌似帖子好看一点
>
>
>
帖子
3347
主题
255
精华
2
可用积分
17554
专家积分
40
在线时间
3576 小时
注册时间
2005-09-14
最后登录
2014-03-21
论坛徽章:
1
原帖由
wwwsq 于 2008-9-3 17:00 发表
返回值是显式的、静态的,异常是隐式的、易变的。
我们这边有个规则,函数有返回值的那么调用者必须检查返回值。如果不知道返回值的含义,那么就查文档、查代码、问人。这个规则简单清晰,职责分明,很 ...
如果一个函数返回10种不同的返回值, 调用者检查这10种不同返回值作不同处理, 这自然是显式的、静态的 但怎么异常就变成是隐式的、易变的呢? 一个返回 int 型的函数可以返回 -1, -3, -n, 1, 2, n 一个抛出 int 的函数也可以抛出 -1, -3, -n, 1, 2, n, 而且我的catch代码照样能获得抛出的int的具体值, 这没有什么两样, 如果你说因为函数声明可以明确知道返回的是 int, 那么很显然, c++也有语法明确可以表示抛出什么异常, 语法是 例如: void throw_int() throw (int){ throw 47; } 你可以说大家都不这么写, 问题是这是大家写不写的问题, 不能说异常的缺点, 就如函数如果没写返回值, 默认返回int型一样 反而, 一个函数可以抛出 int, char*, T型等各种异常, 返回值作不到吧。
上层函数随便猜测了这些异常代表的业务含义,东拼西凑之后总算通过了测试;在某次修改之后,这个函数变成可能会抛出十二种异常,上层调用怎么办
这个不成理由, 如果一个函数返回了十个值, 不说东拼西凑了, 这显得主观; 在某次修改之后,这个函数变成可能会返回十二个值,上层调用怎么办, 如果你能回答出我的, 我就能回答出你的, 恩, 基本上自信可以使用大体相同的句式。 函数有返回值的那么调用者必须检查返回值, 这是人的规定, 不能作为异常的缺陷存在, 因为如果我也定义一个规矩如下: 函数有抛出异常的那么调用这必须检查异常。如果不知道异常的含义,那么就查文档、查代码、问人。这个规则简单清晰,职责分明,很 ... , 那么现在, 你告诉我, 你的认为返回值胜过异常的理由还存在么。 所以说异常返回值都是机制, 没什么谁好谁坏, 审时度势, 具体问题具体分析, 什么合适用什么, 仅此而已。 异常在一定意义上可能不如返回值层层传递来的规整, 但只要写代码的注意分寸即可, 而且这种不规整在一定情况下反而是其优势所在, 你可以说歪打正着, 呵呵, 着了就成了。 这就好比c++与c, 一群人骂c++一堆垃圾特性,问题是你认为垃圾的你可以不用嘛, c++又不是不能写纯c, 自然有用这些特性而且显得不垃圾的代码存在。 具体问题具体分析, 代码质量控制在自己手中而非c++手中, 仅此而已 [ 本帖最后由 zylthinking 于 2008-9-3 19:41 编辑 ]
授我以鱼, 不要授我以渔
找工作, linux 系统编程, 服务器编程 30K 左右
f1_小熊猫
帖子
8692
主题
1132
精华
0
可用积分
2676
专家积分
30
在线时间
3870 小时
注册时间
2007-12-07
最后登录
2014-03-21
论坛徽章:
0
说的是要写,但是以前的人都没处理,这是做signal处理,写日志
帖子
1133
主题
42
精华
0
可用积分
7395
专家积分
10
在线时间
768 小时
注册时间
2005-03-03
最后登录
2013-04-10
论坛徽章:
0
原帖由
zylthinking 于 2008-9-3 19:33 发表
如果一个函数返回10种不同的返回值, 调用者检查这10种不同返回值作不同处理, 这自然是显式的、静态的
但怎么异常就变成是隐式的、易变的呢?
一个返回 int 型的函数可以返回 -1, -3, -n, 1, 2, n
一个抛 ...
"着了就成了",这就是exception的精髓所在,既是优点也是缺点。优点是很快可以写出一个可以工作的软件,缺点是你也不知道它为什么可以工作。 int型的返回值一定会对 -1, -3, -n, 1, 2, n的每个返回值做定义,从此不会多也不会少,除非改接口。这就明确的分离了接口和实现。 exception作为返回值则你无法确定底层会抛出什么异常,因为底层会抛出什么异常,取决于底层的实现方法。如果把抛出的异常看做是接口定义的一部分,那么底层实现的变化将会引起接口的变化,这是不利于封装的;如果你在底层catch所有的异常以保证抛出固定的异常,则这恰恰会隐藏错误。 "函数有抛出异常的那么调用者必须检查异常",这几乎是不可能的,因为函数的实现改了,抛出的异常也很可能会改变,比如在实现里面加上一句obj.do_something()很可能就造成新的异常被抛出。底层函数只有catch所有异常,才能保证自己在实现改变的时候不抛出接口之外的异常,而catch所有异常又会掩盖问题,于是陷入两难。
<
<
<
有个签名貌似帖子好看一点
什么样的问题需要用try catch语句执行
http://zhidao.baidu.com/question/68367165.html?qbl=relate_question_2&word=%CE%D2%D4%F5%C3%B4%D6%AA%B5%C0%C4%C7%C0%EF%D2%AA%C8%A5%C5%D0%B6%CF%20try%20catch
一直对try-catch解决什么问题不太了解,能够捕获的异常如除零异常都是事先定义好的吗?try catch都用来解决什么样了问题,我不太理解多线程为什么用try-catch,鸟儿,麻烦高手指点一下
2008-09-15 15:22
提问者采纳
能够捕获的异常都继承自Exception类。
需要以try-catch捕获的是"可检查"异常,所谓"可检查"异常,是指我们应该自行处理的异常。至于处理的手段,要么加以控制(try catch),要么通告 (throws)他们有可能产生。通常,应捕捉那些已知如何处理的异常,而通告 那些不知如何处理的异常。
java的异常处理 机制要求程序员 必须捕捉"可检查"异常并提供处理方法,或者向更上层抛出该异常。
try-catch能解决的问题就是处理可能出现的异常,打个比方,考虑如下代码:
public void go(){
File file=new File("d:\\a.txt");
FileInputStream fis=null;
try {
fis=new FileInputStream(file);
} catch (FileNotFoundException ex) {
System.out.println("file not found");
ex.printStackTrace();
}
if(fis!=null){//如果找到了文件
……
}
}
代码作用是打开一个文件,如果找不到文件(即捕获到了FileNotFoundException),就给出提示。而找不到文件这样的异常,就属于可能会出现的、可以处理的异常,以这段代码为例try-catch的作用就在于系统找不到文件时不会导致程序出错终止,而是继续往下运行。多线程 为什么用try-catch,其实也是同样的道理。
还有一类是"不可检查"异常,这类异常通常是不可预知的,或者是程序员 无法处理,这类异常程序员 无需考虑,它们要么在我们的控制之外(Error,比如java虚拟机 出错这样的异常),要么是我们首先就不该允许的情况(RuntimeException,LZ所说的除零异常)。
提问者评价
非常感谢,也谢谢其他回答!
其他4条回答
其实很简单 以后你就知道了
如果什么都不写的话
遇到异常 程序立即停止!
如果写了 就会做出异常的 处理
有2种方式 楼上的也说了