Scala函數(shù)式編程(五) 函數(shù)式的錯誤處理

前情提要

Scala函數(shù)式編程指南(一) 函數(shù)式思想介紹

scala函數(shù)式編程(二) scala基礎(chǔ)語法介紹

Scala函數(shù)式編程(三) scala集合和函數(shù)

Scala函數(shù)式編程(四)函數(shù)式的數(shù)據(jù)結(jié)構(gòu) 上

Scala函數(shù)式編程(四)函數(shù)式的數(shù)據(jù)結(jié)構(gòu) 下

1.面向?qū)ο蟮腻e誤處理

在介紹scala的函數(shù)式的錯誤處理之前祖凫,我們要先來介紹一下其他情況下的錯誤處理方式厨剪。

以java為例,常見的錯誤處理方式不外乎兩種扬跋,一種是及時捕捉到異常拌消,然后當(dāng)場進(jìn)行處理。

try{
    ... 
}catch(Exception e){
    ...
    
}finally{
    
}

另一種則是將異常拋出,層層捕獲埃跷,然后在最上層對異常進(jìn)行統(tǒng)一處理,這種通常是在大型項目的時候會使用邮利。

這兩種錯誤處理的方法是弥雹,在我們?nèi)粘5木幊讨校呀?jīng)足以應(yīng)對多種情況延届。

但在函數(shù)式編程中卻不行剪勿,函數(shù)式編程追求的是無副作用的代碼,無副作用最直接的應(yīng)用就是可以放心得并發(fā)運(yùn)行方庭,而拋出異常卻會產(chǎn)生副作用厕吉。

try catch處理的弊端,在并發(fā)編程中其實有較為明顯的體現(xiàn)械念。

以spark為例头朱,如果spark主節(jié)點master詢問worker節(jié)點的健康情況,當(dāng)worker節(jié)點出現(xiàn)異常時龄减,顯然讓master節(jié)點來捕獲并處理這個異常项钮,有點不符合情理。

更合理的處理希停,應(yīng)該是讓master接收到一個表示錯誤情況的消息烁巫,然后再決定接下來如何處理。而worker的異常就讓worker自己去解決吧宠能。

而在scala中程拭,有一種特定的類型,它用來表示可能導(dǎo)致異常的一個計算過程棍潘,這就是Try恃鞋。

2.從Option到Try

前面有介紹過Option,相關(guān)介紹可以看這里Scala函數(shù)式編程(三) scala集合和函數(shù)亦歉。

這里簡單介紹一下Option恤浪。

Option呢,其實就是薛定諤的值肴楷,里面可能有值水由,也可能沒有值。只有到要看的時候赛蔫,才會知道Option里面到底有沒有值砂客。

Option全程叫Option[A]泥张,表示Option里面存的是A類型的值,這個A可以是Int鞠值,String媚创,等等。我們可以通過get這個api來獲取Option[A]里面的值彤恶,當(dāng)不存在時钞钙,get會返回None。

可以通過isEmpty声离,來確認(rèn)Option里面到底是不是有值芒炼。也可以通過getOrElse來指定沒有值的時候要返回什么值。

Try[A]和Option類似术徊,都是表示一個可能有也可能沒有的東西本刽。實際對應(yīng)過來, Try[A]就表示一個可能成功也可以失敗的計算赠涮,如果成功盅安,則返回A類型,如果失敗世囊,則返回Throwable别瞭。

先最在交互式環(huán)境中直觀看一下怎么使用吧:

scala> import scala.util.Try
import scala.util.Try

scala> Try(1+1)
res15: scala.util.Try[Int] = Success(2)

scala> Try(1/0)
res16: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)

能夠?qū)崿F(xiàn)這個功能签钩,主要是因為Try的兩個子類型:

  • Success[A]:代表成功的計算轩端。
  • 封裝了 Throwable 的 Failure[A]:代表出了錯的計算。

是不是和Option很像呢喜德?也是薛定諤的錯誤嗤瞎,在沒打開來看之前墙歪,Try里面可能是成功的,也可能是失敗的贝奇。

同樣可以通過isSuccess和isFailure來確認(rèn)到底這個Try是成功還是失敗虹菲。

如果一個函數(shù)中有一個計算可能會出錯,那么我們就可以直讓函數(shù)返回Try掉瞳,然后對成功還是錯誤毕源,就全交由調(diào)用者來進(jìn)行處理,比如上面說到的陕习,Spark的那個例子霎褐。

3.Try的使用

上面初步介紹了Try的含義和用法,接下來就來看看Try這個東西该镣,還有哪些常規(guī)的用法吧冻璃。

3.1 map

map是scala里面非常常用的一種操作,Try里面也有!

對Try使用Map的話省艳,會將一個是Success[A]的Try[A]映射到Try[B]會得到Success[B]娘纷。如果它是Failure[A],就會得到Failure[B]跋炕,而且包含的異常和Failure[A]一樣赖晶。

看看例子吧:

//新建一個Try,注意枣购,這里是Try[Int]
scala> val tryMap = Try(1+1)
tryMap: scala.util.Try[Int] = Success(2)

//使用Map嬉探,讓它變成Try[String]了
scala> tryMap.map(_.toString)
res46: scala.util.Try[String] = Success(2)

//新建一個會失敗的Try[Int]
scala> val tryMapFail = Try(1 / 0)
tryMapFail: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)

//轉(zhuǎn)換成Try[String]了擦耀,但Failure的異常類型不變
scala> tryMapFail.map(_.toString)
res47: scala.util.Try[String] = Failure(java.lang.ArithmeticException: / by zero)

Try不止支持map棉圈,還支持for,flatMap眷蜓,filter等常規(guī)操作分瘾,從這個角度看,Try反而更像一種數(shù)據(jù)結(jié)構(gòu)吁系。

3.2 錯誤時候的默認(rèn)值getOrElse

和Option一樣德召,Try還很方便得提供了getOrElse這個方法。當(dāng)你想為失敗的時候做些什么的時候就可以用這個api汽纤。

這個我舉個簡單的例子上岗,將字符串轉(zhuǎn)換為Int類型。在字符串轉(zhuǎn)Int類型的時候呢蕴坪,可能會遇到一些不符合規(guī)范的數(shù)據(jù)肴掷。這時候你就不得不考慮數(shù)據(jù)是否可以安全得轉(zhuǎn)換成Int,但有了Try背传,可以很方便得用getOrElse呆瞻,方法。

當(dāng)遇到不能轉(zhuǎn)成Int的字符串径玖,給與一個默認(rèn)值即可痴脾。

scala> import scala.util.Try
import scala.util.Try

scala> "12".toInt
res17: Int = 12

scala> "asd".toInt
java.lang.NumberFormatException: For input string: "asd"
  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
  at java.lang.Integer.parseInt(Integer.java:580)
  at java.lang.Integer.parseInt(Integer.java:615)
  at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
  at scala.collection.immutable.StringOps.toInt(StringOps.scala:29)
  ... 32 elided

scala> Try("asd".toInt).getOrElse(-1)
res19: Int = -1

但這里還是得多說一句,這種做法會忽略掉原本應(yīng)該拋出的錯誤梳星,你需要明確知道自己確實是要忽略掉這個錯誤才能這樣用赞赖。

否則可能因為設(shè)置的默認(rèn)值導(dǎo)致出現(xiàn)問題,而毫無頭緒冤灾,因為程序并沒有報任何錯誤!!

3.3 模式匹配

我們可以不必如java的try catch那般去處理Try失敗時返回的異常薯定。因為我們有scala的模式匹配。

不得不說瞳购,模式匹配真的是很強(qiáng)大的一個語言特性话侄。前面不是說到嘛,Try有兩個子類,Success和Failure年堆,成功時候返回Success吞杭,失敗時返回Failure。

所以我們就能夠這樣做:

import scala.util.Success
import scala.util.Failure
val operation = Try(1 / 0)
operation match {
  case Success(num) => println(num)
  case Failure(ex) => println(s"Problem is ${ex.getMessage}")
}

因為除數(shù)為0变丧,所以這個Try是失敗的芽狗,所以這里會輸出:Problem is / by zero

scala強(qiáng)大的模式匹配,可以方便得讓我們處理錯誤和非錯誤的情況痒蓬。

4. 小結(jié)

Scala 的錯誤處理和其他范式的編程語言有很大的不同童擎。 Try 類型可以讓你將可能會出錯的計算封裝在一個容器里,并優(yōu)雅的去處理計算得到的值攻晒。 并且可以像操作集合和 Option 那樣統(tǒng)一的去操作 Try顾复。

同時Try[A]也支持常見數(shù)據(jù)結(jié)構(gòu)中的操作,諸如Map鲁捏,F(xiàn)ilter等常規(guī)的api都支持芯砸。

Try這種錯誤處理的方式,明顯更適用于函數(shù)式的情況给梅,也就是說更適合在并發(fā)編程的時候使用假丧。

但在我看來,Try也是有一些不好的地方动羽,比如說在代碼可讀性方面就比try catch這種方式差包帚。不得不說,雖然寫起來比較啰嗦运吓,但看著這個結(jié)構(gòu)確實是一目了然渴邦。

但是不管如何,在我看來羽德,函數(shù)式的錯誤處理依舊是很有趣的一個東西几莽。如果合適的話,可以多在代碼中嘗試去使用:)

以上~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宅静,一起剝皮案震驚了整個濱河市章蚣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姨夹,老刑警劉巖纤垂,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異磷账,居然都是意外死亡峭沦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門逃糟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼鱼,“玉大人蓬豁,你說我怎么就攤上這事」剿啵” “怎么了地粪?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長琐谤。 經(jīng)常有香客問我蟆技,道長,這世上最難降的妖魔是什么斗忌? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任质礼,我火速辦了婚禮,結(jié)果婚禮上织阳,老公的妹妹穿的比我還像新娘眶蕉。我一直安慰自己,他們只是感情好陈哑,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布妻坝。 她就那樣靜靜地躺著伸眶,像睡著了一般惊窖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上厘贼,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天界酒,我揣著相機(jī)與錄音,去河邊找鬼嘴秸。 笑死毁欣,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岳掐。 我是一名探鬼主播凭疮,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼串述!你這毒婦竟也來了执解?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤纲酗,失蹤者是張志新(化名)和其女友劉穎衰腌,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體觅赊,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡右蕊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了吮螺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饶囚。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡帕翻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萝风,到底是詐尸還是另有隱情熊咽,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布闹丐,位于F島的核電站横殴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏卿拴。R本人自食惡果不足惜衫仑,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望堕花。 院中可真熱鬧文狱,春花似錦、人聲如沸缘挽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壕曼。三九已至苏研,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腮郊,已是汗流浹背摹蘑。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留轧飞,地道東北人衅鹿。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像过咬,于是被迫代替她去往敵國和親大渤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容