欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

怎么利用Either和Option進(jìn)行函數(shù)式錯(cuò)誤處理

這篇文章給大家分享的是有關(guān)怎么利用Either和Option進(jìn)行函數(shù)式錯(cuò)誤處理的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

我們提供的服務(wù)有:成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、上饒ssl等。為1000+企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的上饒網(wǎng)站制作公司

在 Java 中,錯(cuò)誤的處理在傳統(tǒng)上由異常以及創(chuàng)建和傳播異常的語言支持進(jìn)行。但是,如果不存在結(jié)構(gòu)化異常處理又如何呢?許多函數(shù)式語言不支持異常范式,所以它們必須找到表達(dá)錯(cuò)誤條件的替代方式。在本文中,我將演示 Java 中類型安全的錯(cuò)誤處理機(jī)制,該機(jī)制繞過正常的異常傳播機(jī)制(并通過 Functional Java 框架的一些示例協(xié)助說明)。

函數(shù)式錯(cuò)誤處理

如果您想在 Java 中不使用異常來處理錯(cuò)誤,最根本的障礙是語言的限制,因?yàn)榉椒ㄖ荒芊祷貑蝹€(gè)值。但是,當(dāng)然,方法可以 返回單個(gè) Object(或子類)引用,其中可包含多個(gè)值。那么,我可以使用一個(gè) Map 來啟用多個(gè)返回值。請(qǐng)看看清單 1 中的 pide() 方法:

清單 1. 使用 Map 處理多個(gè)返回值

public static Map<String, Object> pide(int x, int y) {Map<String, Object> result = new HashMap<String, Object>();if (y == 0)result.put("exception", new Exception("p by zero"));elseresult.put("answer", (double) x / y);return result;}

在 清單 1 中,我創(chuàng)建了一個(gè) Map,以 String 為鍵,并以 Object 為值。在 pide() 方法中,我輸出 exception 來表示失敗,或者輸出 answer 來表示成功。清單 2 中對(duì)兩種模式都進(jìn)行了測(cè)試:

清單 2. 使用 Map 測(cè)試成功與失敗

@Testpublic void maps_success() {Map<String, Object> result = RomanNumeralParser.pide(4, 2);assertEquals(2.0, (Double) result.get("answer"), 0.1);}@Testpublic void maps_failure() {Map<String, Object> result = RomanNumeralParser.pide(4, 0);assertEquals("p by zero", ((Exception) result.get("exception")).getMessage());}

在 清單 2 中,maps_success 測(cè)試驗(yàn)證在返回的 Map 中是否存在正確的條目。maps_failure 測(cè)試檢查異常情況。

這種方法有一些明顯的問題。首先,Map 中的結(jié)果無論如何都不是類型安全的,它禁用了編譯器捕獲特定錯(cuò)誤的能力。鍵的枚舉可以略微改善這種情況,但效果不大。其次,該方法調(diào)用器并不知道方法調(diào)用是否成功,這加重了調(diào)用程序的負(fù)擔(dān),它要檢查可能結(jié)果的詞典。第三,沒有什么能阻止這兩個(gè)鍵都有值,這使得結(jié)果模棱兩可。

我需要的是一種讓我能夠以類型安全的方式返回兩個(gè)(或多個(gè))值的機(jī)制。

Either 類

返回兩個(gè)不同值的需求經(jīng)常出現(xiàn)在函數(shù)式語言中,用來模擬這種行為的一個(gè)常用數(shù)據(jù)結(jié)構(gòu)是 Either 類。在 Java 中,我可以使用泛型創(chuàng)建一個(gè)簡(jiǎn)單的 Either 類,如清單 3 所示:

清單 3. 通過 Either 類返回兩個(gè)(類型安全的)值

public class Either<A,B> {private A left = null;private B right = null;private Either(A a,B b) {left = a;right = b;}public static <A,B> Either<A,B> left(A a) {return new Either<A,B>(a,null);}public A left() {return left;}public boolean isLeft() {return left != null;}public boolean isRight() {return right != null;}public B right() {return right;}public static <A,B> Either<A,B> right(B b) {return new Either<A,B>(null,b);}public void fold(F<A> leftOption, F<B> rightOption) {if(right == null)leftOption.f(left);elserightOption.f(right);}}

在 清單 3中,Either 旨在保存一個(gè) left 或 right 值(但從來都不會(huì)同時(shí)保存這兩個(gè)值)。該數(shù)據(jù)結(jié)構(gòu)被稱為不相交并集。一些基于 C 的語言包含 union 數(shù)據(jù)類型,它可以保存含若干種不同類型的一個(gè)實(shí)例。不相交并集的槽可以保存兩種類型,但只保存其中一種類型的一個(gè)實(shí)例。Either 類有一個(gè) private 構(gòu)造函數(shù),使構(gòu)造成為靜態(tài)方法 left(A a) 或 right(B b) 的責(zé)任。在類中的其他方法是輔助程序,負(fù)責(zé)檢索和調(diào)研類的成員。

利用 Either,我可以編寫代碼來返回異常或 一個(gè)合法結(jié)果(但從來都不會(huì)同時(shí)返回兩種結(jié)果),同時(shí)保持類型安全。常見的函數(shù)式約定是 Either 類的 left 包含異常(如有),而 right 包含結(jié)果。

解析羅馬數(shù)字

我有一個(gè)名為 RomanNumeral 的類(我將其實(shí)現(xiàn)留給讀者去想象)和一個(gè)名為 RomanNumeralParser 的類,該類調(diào)用 RomanNumeral 類。parseNumber() 方法和說明性測(cè)試如清單 4 所示:

清單 4. 解析羅馬數(shù)字

public static Either<Exception, Integer> parseNumber(String s) {if (! s.matches("[IVXLXCDM]+"))return Either.left(new Exception("Invalid Roman numeral"));elsereturn Either.right(new RomanNumeral(s).toInt());}@Testpublic void parsing_success() {Either<Exception, Integer> result = RomanNumeralParser.parseNumber("XLII");assertEquals(Integer.valueOf(42), result.right());}@Testpublic void parsing_failure() {Either<Exception, Integer> result = RomanNumeralParser.parseNumber("FOO");assertEquals(INVALID_ROMAN_NUMERAL, result.left().getMessage());}

在 清單 4 中,parseNumber() 方法執(zhí)行一個(gè)驗(yàn)證(用于顯示錯(cuò)誤),將錯(cuò)誤條件放置在 Either 的 left 中,或?qū)⒔Y(jié)果放在它的 right中。單元測(cè)試中顯示了這兩種情況。

比起到處傳遞 Map,這是一個(gè)很大的改進(jìn)。我保持類型安全(請(qǐng)注意,我可以按自己喜歡使異常盡量具體);在通過泛型的方法聲明中,錯(cuò)誤是明顯的;返回的結(jié)果帶有一個(gè)額外的間接級(jí)別,可以解壓 Either 的結(jié)果(是異常還是答案)。額外的間接級(jí)別支持惰性。

惰性解析和 Functional Java

Either 類出現(xiàn)在許多函數(shù)式算法中,并且在函數(shù)式世界中如此之常見,以致 Functional Java 框架(參閱 參考資料)也包含了一個(gè) Either 實(shí)現(xiàn),該實(shí)現(xiàn)將在 清單 3 和 清單 4 的示例中使用。但它的目的就是與其他 Functional Java 構(gòu)造配合使用。因此,我可以結(jié)合使用 Either 和 Functional Java 的 P1 類來創(chuàng)建惰性 錯(cuò)誤評(píng)估。惰性表達(dá)式是一個(gè)按需執(zhí)行的表達(dá)式(參閱 參考資料)。

在 Functional Java 中,P1 類是一個(gè)簡(jiǎn)單的包裝器,包括名為 _1() 的方法,該方法不帶任何參數(shù)。(其他變體:P2 和 P3 等,包含多種方法。)P1 在 Functional Java 中用于傳遞一個(gè)代碼塊,而不執(zhí)行它,使您能夠在自己選擇的上下文中執(zhí)行代碼。

在 Java 中,只要您 throw 一個(gè)異常,異常就會(huì)被實(shí)例化。通過返回一個(gè)惰性評(píng)估的方法,我可以將異常創(chuàng)建推遲到以后。請(qǐng)看看清單 5 中的示例及相關(guān)測(cè)試:

清單 5. 使用 Functional Java 創(chuàng)建一個(gè)惰性解析器

public static P1<Either<Exception, Integer>> parseNumberLazy(final String s) {if (! s.matches("[IVXLXCDM]+"))return new P1<Either<Exception, Integer>>() {public Either<Exception, Integer> _1() {return Either.left(new Exception("Invalid Roman numeral"));}};elsereturn new P1<Either<Exception, Integer>>() {public Either<Exception, Integer> _1() {return Either.right(new RomanNumeral(s).toInt());}};}@Testpublic void parse_lazy() {P1<Either<Exception, Integer>> result = FjRomanNumeralParser.parseNumberLazy("XLII");assertEquals((long) 42, (long) result._1().right().value());}@Testpublic void parse_lazy_exception() {P1<Either<Exception, Integer>> result = FjRomanNumeralParser.parseNumberLazy("FOO");assertTrue(result._1().isLeft());assertEquals(INVALID_ROMAN_NUMERAL, result._1().left().value().getMessage());}

清單 5 中的代碼與 清單 4 中的類似,但多了一個(gè) P1 包裝器。在 parse_lazy 測(cè)試中,我必須通過在結(jié)果上調(diào)用 _1() 來解壓結(jié)果,該方法返回 Either 的 right,從該返回值中,我可以檢索值。在 parse_lazy_exception 測(cè)試中,我可以檢查是否存在一個(gè) left,并且我可以解壓異常,以辨別它的消息。

在您調(diào)用 _1() 解壓 Either 的 left 之前,異常(連同其生成成本昂貴的堆棧跟蹤)不會(huì)被創(chuàng)建。因此,異常是惰性的,讓您推遲異常的構(gòu)造程序的執(zhí)行。

提供默認(rèn)值

惰性不是使用 Either 進(jìn)行錯(cuò)誤處理的惟一好處。另一個(gè)好處是,您可以提供默認(rèn)值。請(qǐng)看清單 6 中的代碼:

清單 6. 提供合理的默認(rèn)返回值

public static Either<Exception, Integer> parseNumberDefaults(final String s) {if (! s.matches("[IVXLXCDM]+"))return Either.left(new Exception("Invalid Roman numeral"));else {int number = new RomanNumeral(s).toInt();return Either.right(new RomanNumeral(number >= MAX ? MAX : number).toInt());}}@Testpublic void parse_defaults_normal() {Either<Exception, Integer> result = FjRomanNumeralParser.parseNumberDefaults("XLII");assertEquals((long) 42, (long) result.right().value());}@Testpublic void parse_defaults_triggered() {Either<Exception, Integer> result = FjRomanNumeralParser.parseNumberDefaults("MM");assertEquals((long) 1000, (long) result.right().value());}

在 清單 6 中,假設(shè)我不接受任何大于 MAX 的羅馬數(shù)字,任何企圖大于該值的數(shù)字都將被默認(rèn)設(shè)置為 MAX。parseNumberDefaults() 方法確保默認(rèn)值被放置在 Either 的 right 中。

包裝異常

我也可以使用 Either 來包裝異常,將結(jié)構(gòu)化異常處理轉(zhuǎn)換成函數(shù)式,如清單 7 所示:

清單 7. 捕獲其他人的異常

public static Either<Exception, Integer> pide(int x, int y) {try {return Either.right(x / y);} catch (Exception e) {return Either.left(e);}}@Testpublic void catching_other_people_exceptions() {Either<Exception, Integer> result = FjRomanNumeralParser.pide(4, 2);assertEquals((long) 2, (long) result.right().value());Either<Exception, Integer> failure = FjRomanNumeralParser.pide(4, 0);assertEquals("/ by zero", failure.left().value().getMessage());}

在 清單 7 中,我嘗試除法,這可能引發(fā)一個(gè) ArithmeticException。如果發(fā)生異常,我將它包裝在 Either 的 left 中;否則我在 right 中返回結(jié)果。使用 Either 使您可以將傳統(tǒng)的異常(包括檢查的異常)轉(zhuǎn)換成更偏向于函數(shù)式的風(fēng)格。

當(dāng)然,您也可以惰性包裝從被調(diào)用的方法拋出的異常,如清單 8 所示:

清單 8. 惰性捕獲異常

public static P1<Either<Exception, Integer>> pideLazily(final int x, final int y) {return new P1<Either<Exception, Integer>>() {public Either<Exception, Integer> _1() {try {return Either.right(x / y);} catch (Exception e) {return Either.left(e);}}};}@Testpublic void lazily_catching_other_people_exceptions() {P1<Either<Exception, Integer>> result = FjRomanNumeralParser.pideLazily(4, 2);assertEquals((long) 2, (long) result._1().right().value());P1<Either<Exception, Integer>> failure = FjRomanNumeralParser.pideLazily(4, 0);assertEquals("/ by zero", failure._1().left().value().getMessage());}

嵌套異常

Java 異常有一個(gè)不錯(cuò)的特性,它能夠?qū)⑷舾煞N不同的潛在異常類型聲明為方法簽名的一部分。盡管語法越來越復(fù)雜,但 Either 也可以做到這一點(diǎn)。例如,如果我需要 RomanNumeralParser 上的一個(gè)方法允許我對(duì)兩個(gè)羅馬數(shù)字執(zhí)行除法,但我需要返回兩種不同的可能異常情況,那么是解析錯(cuò)誤還是除法錯(cuò)誤?使用標(biāo)準(zhǔn)的 Java 泛型,我可以嵌套異常,如清單 9 所示:

清單 9. 嵌套異常

public static Either<NumberFormatException, Either<ArithmeticException, Double>> pideRoman(final String x, final String y) {Either<Exception, Integer> possibleX = parseNumber(x);Either<Exception, Integer> possibleY = parseNumber(y);if (possibleX.isLeft() || possibleY.isLeft())return Either.left(new NumberFormatException("invalid parameter"));int intY = possibleY.right().value().intValue();Either<ArithmeticException, Double> errorForY = Either.left(new ArithmeticException("p by 1"));if (intY == 1)return Either.right((fj.data.Either<ArithmeticException, Double>) errorForY);int intX = possibleX.right().value().intValue();Either<ArithmeticException, Double> result = Either.right(new Double((double) intX) / intY);return Either.right(result);}@Testpublic void test_pide_romans_success() {fj.data.Either<NumberFormatException, Either<ArithmeticException, Double>> result = FjRomanNumeralParser.pideRoman("IV", "II");assertEquals(2.0,result.right().value().right().value().doubleValue(), 0.1);}@Testpublic void test_pide_romans_number_format_error() {Either<NumberFormatException, Either<ArithmeticException, Double>> result = FjRomanNumeralParser.pideRoman("IVooo", "II");assertEquals("invalid parameter", result.left().value().getMessage());}@Testpublic void test_pide_romans_arthmetic_exception() {Either<NumberFormatException, Either<ArithmeticException, Double>> result = FjRomanNumeralParser.pideRoman("IV", "I");assertEquals("p by 1", result.right().value().left().value().getMessage());}

在 清單 9 中,pideRoman() 方法首先解壓從 清單 4 的原始 parseNumber() 方法返回的 Either。如果在這兩次數(shù)字轉(zhuǎn)換的任一次中發(fā)生一個(gè)異常,Either left 與異常一同返回。接下來,我必須解壓實(shí)際的整數(shù)值,然后執(zhí)行其他驗(yàn)證標(biāo)準(zhǔn)。羅馬數(shù)字沒有零的概念,所以我制定了一個(gè)規(guī)則,不允許除數(shù)為 1:如果分母是 1,我打包我的異常,并放置在 right 的 left 中。

換句話說,我有三個(gè)槽,按類型劃分:NumberFormatException、ArithmeticException 和 Double。第一個(gè) Either 的 left 保存潛在的 NumberFormatException,它的 right 保存另一個(gè) Either。第二個(gè) Either 的 left 包含一個(gè)潛在的 ArithmeticException,它的 right 包含有效載荷,即結(jié)果。因此,為了得到實(shí)際的答案,我必須遍歷 result.right().value().right().value().doubleValue()!顯然,這種方法的實(shí)用性迅速瓦解,但它確實(shí)提供了一個(gè)類型安全的方式,將異常嵌套為類簽名的一部分。

Option 類

Either 是一個(gè)方便的概念,在下期文章中,我將使用這個(gè)概念構(gòu)建樹形數(shù)據(jù)結(jié)構(gòu)。Scala 中有一個(gè)名為 Option 的類與之類似,該類在 Functional Java 中被復(fù)制,提供了一個(gè)更簡(jiǎn)單的異常情況:none 表示不合法的值,some 表示成功返回。Option 如清單 10 所示:

清單 10. 使用 Option

public static Option<Double> pide(double x, double y) {if (y == 0)return Option.none();return Option.some(x / y);}@Testpublic void option_test_success() {Option result = FjRomanNumeralParser.pide(4.0, 2);assertEquals(2.0, (Double) result.some(), 0.1);}@Testpublic void option_test_failure() {Option result = FjRomanNumeralParser.pide(4.0, 0);assertEquals(Option.none(), result);}

如 清單 10 所示,Option 包含 none() 或 some(),類似于 Either 中的 left 和 right,但特定于可能沒有合法返回值的方法。

Functional Java 中的 Either 和 Option 都是單體,表示計(jì)算 的特殊數(shù)據(jù)結(jié)構(gòu),在函數(shù)式語言中大量使用。在下一期中,我將探討有關(guān) Either 的單體概念,并在不同的示例中演示它如何支持 Scala 風(fēng)格的模式匹配。

感謝各位的閱讀!關(guān)于“怎么利用Either和Option進(jìn)行函數(shù)式錯(cuò)誤處理”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

當(dāng)前文章:怎么利用Either和Option進(jìn)行函數(shù)式錯(cuò)誤處理
標(biāo)題來源:http://aaarwkj.com/article20/jegdco.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站制作建站公司、靜態(tài)網(wǎng)站、

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
国产剧情av网址观看免费| 日韩一区二区三区不卡| 人妻乱人伦中文字幕在线| 中文字幕一区二区精品区| 亚洲高清有码在线观看| 中国吞精囗交免费视频| 午夜久久精品国产亚洲av | 特级艳片在线观看免费| 精品一区精品二区国产日韩| 日本的一级片一区二区| 亚洲第一国产综合自拍| 久久久久久这里都是精品| 国产综合永久精品日韩鬼片 | 国产精品盗摄一区二区三区| 亚洲国产精品久久久久久99| 亚洲精品一区国产精品av| 亚洲欧美丝袜清纯另类| 日韩中文字幕一二一二区 | 亚洲欧洲日产国码一区| 久久久亚洲福利精品午夜| 人妻猛烈进入中文字幕| 国产精品网站在线观看| 精品人妻在线中文字幕| 日韩欧美亚洲制服丝袜| 少妇高潮喷水下面的水| 久久亚洲女同第一区综合| 国产精品播放一区二区三区| 人妻巨乳一区二区三区| 九九视频在线观看免费专区| 亚洲中文字幕伦理在线| 欧美精品国产欧美精品国产| 日韩亚洲一区在线观看| 日本色电影一区二区三区| 亚洲黄色成人免费观看| 日日做日夜夜操天天搞| 在线国产精品中文字幕| 久久精品亚洲天然东京热| 亚洲一区二区三区不卡视频 | 91精品在线观看第一页| 欧美一区二区三区高清正版| 中文字幕乱码一区二区欧美|