作者PsMonkey (痞子军团团长)
看板java
标题Re: [问题] 程式的例外
时间Tue Apr 16 01:15:23 2013
这是一个很好的问题
好到我觉得今天早上应该多烧三柱香感谢祖先 [意义不明]
这个问题也有点大,说不定可以写一本书?
我也不是什麽 master 还是啥鬼的
仓促随手写到哪算到哪
只能说希望有抛砖引玉的效果
※ 引述《Shrugg (泪眼问花花不语)》之铭言:
: 想请问一个一直都没办法在逻辑上说服自己的观念性问题
: 参考资料都说,程式的例外是用来撷取runtime时的例外情形,用来拦截例外的发生的.
: 可是要是已经知道会有那些例外可能发生,
: 设计程式时我们不是就会把限制条件给加上去了,
: 根本不用等到例外发生了再来拦截吧?
: Runtime会发生的例外都是设计程式时根本没想到的,既然没想到,
: 为什麽会知道要怎麽去预防呢?
: 像旗标的Java2第十四章以一个使用者输入错误当例子,程式例只能输入数字
: 但当使用者输入字串时就会是一个例外,所以程式安排这边设计一个拦截字串例外
: 发生时的处理.
: 但是假设我是这个程式的开发者
: 我要是一开始就知道这个例外的存在,我就会设条件让使用者不能输入数字以外的资料了
: 如果我连这个例外都没有预估到,我又怎麽会知道要去拦截这个例外呢?
: 希望有人知道我在说甚麽
我觉得看待 exception 机制,得两方面都着眼
一个是炸 exception 的程式,也就是被呼叫、被使唤的 callee
一个是被炸 exception 的程式,也就是呼叫别人的 caller
单纯从 callee 的角度来看 exception 机制
很容易就会得到你的结论
甚至会觉得 exception 机制真的自找麻烦
还得生出一堆 exception class(Java 人最爱生物件了 [死])
那麽,先换个位置也换个脑袋
从 caller 的角度来看呢?
我常常会说 caller 其实就是上司
吩咐 callee 属下去作一件他不想自己作的事情
假设是买便当好了,所以你会设计一个买便当专员
public class 跑腿 {
public static 便当 买便当(需求 request, 预算 money) {
//根据需求跟预算来决定回传什麽便当
}
}
当午餐时间到了,你可能就这样作
便当 bandon = 跑腿.买便当(
this.想午餐要吃什麽(new Date()),
this.钱包.全部的钱
);
this.吃(bandon);
如果按照你的说法
> 设计程式时我们不是就会把限制条件给加上去了,
> 根本不用等到例外发生了再来拦截吧?
套用在 caller 上会怎麽样呢?
//钱包至少要有钱
if (this.钱包.is没钱()) {
//准备饿肚子
}
//钱包里头的钱要大於要买的便当
需求 午餐需求 = this.想午餐要吃什麽(new Date());
if (this.钱包.全部的钱 < 午餐需求.金额 ) {
//准备饿肚子
}
便当 bandon = 跑腿.买便当(
午餐需求,
this.钱包.全部的钱
);
this.吃(bandon);
等等,这不科学阿...
我是主管耶... 我一秒钟几十万上下
我还得自己去确认钱包里头的钱、确认钱够买午餐?
喵的,这不能叫跑腿自己确认就好了吗?
不然这跑腿也太没用了吧? 可以 fire 掉换一个强一点的吗?
我只要告诉他我的需求、给他我的钱包就好
就像一开始的那样
便当 bandon = 跑腿.买便当(
this.想午餐要吃什麽(new Date()),
this.钱包.全部的钱
);
this.吃(bandon);
最好钱不够他还会自己先垫钱最好...
(完美跑腿:我会去地下钱庄借钱,挂你的名字 [指])
於是叫 HR 去应徵一个新的跑腿
public class 跑腿v2 {
public static 便当 买便当(需求 request, 预算 money) {
if (money <= 0) {
//没钱买个屁阿?
}
if (money < request.金额) {
//钱不够买个屁阿?
}
//根据需求跟预算来决定回传什麽便当
}
}
结果主管眉头一皱,发现便当并不单纯
因为无论是「没钱买屁」还是「钱不够买屁」
(对不起,这个跑腿讲话比较粗俗)
都得等跑腿v2 买完回来之後
打开便当发现里头只有屁味
才知道还是没便当可吃
更惨的是,我还得仔细去分辨是哪种味道
才能了解到底是我根本没给跑腿钱、还是钱给不够
便当 bandon = 跑腿.买便当(
this.想午餐要吃什麽(new Date()),
this.钱包.全部的钱
);
if (bandon.is没钱买屁() ) {
//...
} else if (bandon.is钱不够买屁() ) {
//...
} else {
//终於可以吃便当
this.吃(bandon);
}
这就更奇怪了,谁会期望便当会有屁味?
何止是愚蠢,简直就是愚蠢!这公平吗?乡亲们答应吗?
(谜之声:先生你又跑错棚了)
为甚麽跑腿不能在没办法正常买到便当的时候
直接告诉我:「我发生意外了... Orz」
这样如果我没有收到意外的讯息
那就表示拿到便当的时候我可以放心吸气、大口咬下
try {
便当 bandon = 跑腿.买便当(
this.想午餐要吃什麽(new Date()),
this.钱包.全部的钱
);
this.吃(bandon);
} catch (Exception e) {
//处理意外
}
所以叫 HR 去找会丢 exception 的跑腿v3
public class 跑腿v3 {
public static 便当 买便当(需求 request, 预算 money)
throws 买便当意外 {
if (money <= 0) {
throw new 没钱买便当意外();
}
if (money < request.金额) {
//顺便告诉我差了多少钱
throw new 前不够买便当意外( request.金额 - money );
}
//根据需求跟预算来决定回传什麽便当
}
}
所以我就只要这样处理就可以了
try {
便当 bandon = 跑腿.买便当(
this.想午餐要吃什麽(new Date()),
this.钱包.全部的钱
);
this.吃(bandon);
} catch (没钱买便当意外 e1) {
//赶快借钱塞进钱包
} catch (钱不够买便当意外 e2) {
int 差多少 = e2.get差额();
//差不太多就补足、差太多就需求变更吧 [远目]
}
hmmm... 等等,虽然现在跑腿v3 只能告诉我这两个意外
但是我还是可以先把其他想到的意外先设想要怎麽处理
等到 22k 可以请到博士来当完美跑腿的时候
我的买便当应变对策也不用再回头再修改
现在的跑腿也还是可以继续撑着用
甚至 HR 还知道要用什麽条件去找完美跑腿,所以
try {
便当 bandon = 跑腿.买便当(
this.想午餐要吃什麽(new Date()),
this.钱包.全部的钱
);
this.吃(bandon);
} catch (没钱买便当意外 e1) {
//赶快借钱塞进钱包
} catch (钱不够买便当意外 e2) {
int 差多少 = e2.get差额();
//差不太多就补足、差太多就需求变更吧 [远目]
} catch (便当卖完意外 e3) {
//需求变更吧... 只是同一家店卖的东西不要再点了
} catch (食材灭绝意外 wtf) {
//赶快呼叫铁平
}
这样子举例下来,有稍微解答了你的疑惑了吗?
至於其他没有提到 or 我不会的部份
就有请各方高手开示指正了 Orz
_____________________________________________________________________
突然想到 n 久以前写的
《[新手止难] 为什麽有些东西要弄得那麽复杂?》
想到这一夜里头《四郎探母》那句
「阿... 真老阿......」
原来我依然一事无成
--
钱锺书:
说出来的话
http://www.psmonkey.org
比不上不说出来的话
Java 版 cookcomic 版
只影射着说不出来的话
and more......
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 1.162.249.163
1F:→ cha122977:你回这篇回的好嗨XD 04/16 03:33
2F:→ cha122977:还有不用侦测回传值就能处理 & 会直接离开try等好处 04/16 03:52
3F:推 jtmh:推~ 04/16 04:42
4F:推 er230059:这篇太有才了 04/16 08:50
5F:推 DeathWatch:为什麽你讲四郎我想到甄嬛叫四郎~ 04/16 09:18
6F:推 lashante:excellent!! 04/16 10:08
7F:推 makeabomb:浅显易懂, 那个"屁啦~"是精典 04/16 10:36
8F:推 herbert1012:该推! 04/16 10:52
9F:推 kewang:大推这篇! 04/16 19:49
10F:推 adern9:回得好拚啊 推 04/16 22:50
11F:推 KeySabre:好文 04/19 01:23