摘要:在目前的工作中,我對中的和表達式都使用得很多,之前也寫了兩篇文章來總結對應的知識。為了避免,他們會加很多判斷語句,使得代碼的可讀性變得很差。在后面的開發(fā)中,可以使用設計,這樣可以設計出更安全的接口和方法。
在目前的工作中,我對Java中的Stream和Lambda表達式都使用得很多,之前也寫了兩篇文章來總結對應的知識。
024:Java流實現(xiàn)Shell:cat 1.log | grep a | sort | uniq -c | sort -rn
函數(shù)式編程讓你忘記設計模式
不過對于Optional這個特性,一直沒有很好地使用起來,所以最近又開始閱讀《Java 8實戰(zhàn)》這本書,本文是針對其中第10章的一個學習總結。
背景在Java中,如果你嘗試對null做函數(shù)調(diào)用,就會引發(fā)NullPointerException(NPE),NPE是Java程序開發(fā)中的最典型的異常,對于Java開發(fā)者來說,無論你是初出茅廬的新人和還工作多年的老司機,NPE經(jīng)常讓他們翻車。為了避免NPE,他們會加很多if判斷語句,使得代碼的可讀性變得很差。
從軟件設計的角度來看,null本身是沒有意義的語義,這是一種對缺失變量值的錯誤的建模。
從Java類型系統(tǒng)的角度看,null可以被賦值給任何類型的變量,并且不斷被傳遞,知道最后誰也不知道它是從哪里引入的。
Optional的引入Java設計者從Haskell和Scala中獲取靈感,在Java 8中引入了一個新的類java.util.Optional
Optional的目的就在于此:通過類型系統(tǒng)讓你的領域模型中隱藏的知識顯式地體現(xiàn)在你的代碼中。
Optional的使用方法 | 描述 |
---|---|
empty | 返回一個空的Optional實例 |
filter | 如果值存在并且滿足提供的過濾條件,則返回包含該值的Optional對象;否則就返回一個空的Optional對象 |
map | 如果值存在,就對該值執(zhí)行提供的mapping函數(shù)調(diào)用 |
flatMap | 如果值存在,就對該值執(zhí)行提供的mapping函數(shù)調(diào)用,返回一個Optional類型的值,否則就返回一個空的Optional對象 |
ifPresent | 如果值存在,就執(zhí)行使用該值的方法調(diào)用,否則什么也不做 |
of | 將指定值用Optional封裝之后返回,如果該值為null,則拋出一個NPE |
ofNullable | 將指定值用Optional封裝之后返回,如果該值為null,則返回一個空的Optional對象 |
orElse | 如果有值則返回,否則返回一個默認值 |
orElseGet | 如果有值則返回,否則返回一個由指定的Supplier接口生成的值(如果默認值的生成代價比較高的話,則適合使用orElseGet方法) |
orElseThrow | 如果有值則返回,否則返回一個由指定的Supplier接口拋出的異常 |
get | 如果值存在,則返回該值,否則拋出一個NoSuchElementException異常 |
isPresent | 如果值存在則返回true,否則返回false |
上面這張表里列舉了Optional的基礎API,我這里列舉了一些使用的tips:
你可以用ofNullable將一個可能為null的對象封裝為Optional對象,然后獲取值的時候使用orElse方法提供默認值;可以使用empty方法創(chuàng)建一個空的Optional對象;of方法一般不用,不過如果你知道某個值不可能為null,則可以用Optional封裝該值,這樣它一旦為null就會拋出異常。
//empty方法的使用 OptionaloptCar = Optional.empty(); //of方法的使用 Optional optCar = Optional.of(car); //ofNullable方法的使用 Optional optCar = Optional.ofNullable(car);
你可以使用map方法從Optional
OptionaloptInsurance = Optional.ofNullable(insurance); Optional name = optInsurance.map(Insurance::getName);
如果需要連續(xù)、層層遞進的從某個對象鏈的末端獲取字段的值,則不能全部使用map方法,需要先使用flatMap,最后再使用map方法;
//轉換之前 public String getCarInsuranceName(Person person) { return person.getCar().getInsurance().getName(); } //轉換后 public String getCarInsuranceName(Optionalperson) { return person.flatMap(Person::getCar) .flatMap(Car::Insurance) .map(Insurance::getName) .orElse("Unknown"); }
Optional中的map、flatMap和filter方法,在概念是與Stream中對應的方法都很類似,區(qū)別就在于Optional中的元素至多有一個,算是Stream的一種特殊情況——一種特殊的集合。
不要使用ifPresent和get方法,它們本質上和不適用Optional對象之前的模式相同,都是臃腫的if-then-else判斷語句;
由于Optional無法序列化,所以在領域模型中,無法將某個字段定義為Optional
public class Person { private Car car; public OptionalgetCarAsOptional() { return Optional.ofNullable(car); } }
不要使用基礎類型的Optional對象,原因是:基礎類型的Optional對象不支持map、flatMap和filter方法,而這些方法是Optional中非常強大的方法。
實戰(zhàn)案例 案例1:使用工具類方法改良可能拋出異常的APIJava方法處理異常結果的方式有兩種:返回null(或錯誤碼);拋出異常,例如:Integer.parseInt(String)這個方法——如果無法解析到對應的整型,該方法就拋出一個NumberFormationException,這種情況下我們一般會使用try/catch語句處理異常情況。
一般我們建議將try/catch塊多帶帶提取到一個方法中,在這里使用Optional設計這個方法,代碼如下。在開發(fā)中,可以嘗試構建一個OptionalUtility工具類,將這些復雜的try/catch邏輯封裝起來。
public static Optional案例2:綜合案例stringToInt(String a) { try{ return Optional.of(Integer.parseInt(s)); } catch (NumberFormationException e) { return Optional.empty(); } }
現(xiàn)在有個方法,是嘗試從一個屬性映射中獲取某個關鍵詞對應的值,例子代碼如下:
public static int readDuration(Properties properties, String name) { String value = properties.getProperty(name); if (value != null) { try { int i = Integer.parseInt(value); if (i > 0) { return i; } } catch (NumberFormatException e) { } } return 0; }
使用Optional的寫法后,代碼如下所示:
public static int readDurationWithOptional(Properties properties, String name) { return Optional.ofNullable(properties.getProperty(name)) .flatMap(OptionalUtility::stringToInt) .filter(integer -> integer > 0) .orElse(0); }
如果需要訪問的屬性值不存在,Properites.getProperty(String)方法的返回值就是一個null,使用noNullable工廠方法就可以將該值轉換為Optional對象;接下來,可以使用flatMap將一個Optional
使用Optional的思路和Stream相同,都是鏈式思路,跟數(shù)據(jù)庫查詢似的,表達力很強,而且省去了哪些復雜的try/catch和if-then-else方法。在后面的開發(fā)中,可以使用Optional設計API,這樣可以設計出更安全的接口和方法。
本號專注于后端技術、JVM問題排查和優(yōu)化、Java面試題、個人成長和自我管理等主題,為讀者提供一線開發(fā)者的工作和成長經(jīng)驗,期待你能在這里有所收獲。
本號專注于后端技術、JVM問題排查和優(yōu)化、Java面試題、個人成長和自我管理等主題,為讀者提供一線開發(fā)者的工作和成長經(jīng)驗,期待你能在這里有所收獲。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/75392.html
摘要:從開始,您可以通過返回來避免。例如,此方法返回一個空的,而不是返回可選獲取指定的卡片內(nèi)容的代碼從JDK 8開始,您可以通過返回Optional來避免NullPointerException。 例如,此方法返回一個空的Optional:,而不是返回null public可選fetchShoppingCart(long id){ ???? ShoppingCart cart = //獲取...
大概一年多之前,我對java8的理解還僅限一些只言片語的文章之上,后來出于對函數(shù)式編程的興趣,買了本參考書看了一遍,然后放在了書架上,后來,當我接手大客戶應用的開發(fā)工作之后,java8的一些工具,對我的效率有了不小的提升,因此想記錄一下java8的一些常用場景,我希望這會成為一個小字典,能讓我免于頻繁翻書,但是總能找到自己想找的知識。 用于舉例的model: @Data public class ...
摘要:接口例子如果容器的對象存在,則對其執(zhí)行調(diào)用函數(shù)得到返回值。上面一句代碼對應著最開始的老寫法方法直接看源碼方法與方法類似,區(qū)別在于函數(shù)的返回值不同。 前言 只有光頭才能變強 前兩天帶女朋友去圖書館了,隨手就給她來了一本《與孩子一起學編程》的書,于是今天就給女朋友講解一下什么是Optional類。 至于她能不能看懂,那肯定是看不懂的。(學到變量/for循環(huán)的女人怎么能看懂呢) 不知道大家還...
摘要:本文已收錄修煉內(nèi)功躍遷之路的為解決空的問題帶來了很多新思路,查看源碼,實現(xiàn)非常簡單,邏輯也并不復雜。 本文已收錄【修煉內(nèi)功】躍遷之路 showImg(https://segmentfault.com/img/bVbrCvp?w=852&h=480); Java8的Optional為解決空的問題帶來了很多新思路,查看Optional源碼,實現(xiàn)非常簡單,邏輯也并不復雜。Stuart Ma...
摘要:新特性總覽標簽本文主要介紹的新特性,包括表達式方法引用流默認方法組合式異步編程新的時間,等等各個方面。還有對應的和類型的函數(shù)連接字符串廣義的歸約匯總起始值,映射方法,二元結合二元結合。使用并行流時要注意避免共享可變狀態(tài)。 Java8新特性總覽 標簽: java [TOC] 本文主要介紹 Java 8 的新特性,包括 Lambda 表達式、方法引用、流(Stream API)、默認方...
閱讀 1361·2021-11-24 09:39
閱讀 1354·2021-11-04 16:12
閱讀 2697·2021-09-24 09:47
閱讀 3343·2021-09-01 10:50
閱讀 1482·2019-08-30 15:55
閱讀 1429·2019-08-30 15:43
閱讀 650·2019-08-30 11:08
閱讀 3587·2019-08-23 18:33