如何理解Java8 的函數式編程

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 出現的時間已經不算短了,免費維護期馬上也要到期了,官方已經開始推薦使用 Java11。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 是革命性的一個版本,一直以來,Java 最受詬病的地方就是代碼寫起來很囉嗦,僅僅寫一個 HelloWorld 都需要些很多的樣板代碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Java8 推出之後,囉嗦的代碼有了很大的改觀,Java 也可以寫出簡單優美的代碼。最明顯的改觀就是 Java 開始支持函數式編程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數式編程的定義很晦澀,但是我們可以將函數式編程理解爲函數本身可以作爲參數進行傳遞,就是說,參數不僅僅可以是數據,也可以是行爲(函數或者方法的實現其實就是邏輯行爲)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可能是 Java8 步子跨的太大,以至於現在還有很多人沒有趕上來,依然用 Java8 在寫 Java5 風格的代碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這篇文章的目的就是徹底說清楚 Java8 的變化,以及快速全面的使用 Java8 的特性,讓 Java 代碼優雅起來。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"函數式接口"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在開始說 Java8 的函數式編程之前,我們需要說明一下,在 Java8 中新增加的一個概念,叫"},{"type":"text","marks":[{"type":"strong"}],"text":"函數式接口"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個函數式接口是 Java8 實現函數式編程的基礎,正是這類接口的存在,才能把函數(方法)當做參數進行傳遞,至少表面上看起來是這樣的,但是實際上傳遞的還是對象,這個問題我們下面再討論,先回到函數式接口。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面就是一個函數式接口:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"public interface Action {\n public void action();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個函數式看起來和普通的接口沒有什麼區別,唯一的區別是函數式接口只能有"},{"type":"text","marks":[{"type":"strong"}],"text":"一個抽象方法"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你想讓別人立馬理解這個接口是函數式接口,可以加上 "},{"type":"codeinline","content":[{"type":"text","text":"@FunctionalInterface"}]},{"type":"text","text":" 註解,這個註解不會提供任何額外的功能,僅僅用來表示這個接口是一個函數式接口。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@FunctionalInterface\npublic interface Action {\n public void action();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"只能有一個抽象方法是爲了更方便的把函數作爲參數來傳遞,這個後面再細說。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們可以根據自己的需要來定義函數式接口,JDK 爲了使用方便,內置了很多函數式接口,日常使用完全夠了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"常用的函數接口有:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Function"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Predicate"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Consumer"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數式接口其實就這麼簡單,看到這裏你可能還是對函數式接口不是很理解,沒關係,現在你僅僅只需要記住"},{"type":"text","marks":[{"type":"strong"}],"text":"函數式接口就是模板"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Lambda 表達式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"說起 Java8 的函數式編程,很多人都知道 lambda 表達式,這也是 Java8 中最容易被人記住的地方。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先來通過一個直觀的例子來了解一下 lambda,在操作 ArrayList 等數據結構時,我們有可能要對其中的數據進行排序,比如:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Comparator comparator = new Comparator() {\n public int compare(Integer i1, Integer i2) {\n return i1.comparaTo(i2);\n }\n};"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上面的代碼中,真正有用的代碼也有比較大小的那行,其他的都是樣板代碼。在這樣的情況下,lambda 就很有用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Comparator comparator = (Integer i1, Integer i2) -> {return i1.compareTo(i2);}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣看起來是不是很簡單了,但是還是繼續優化,可以把返回參數的部分也省略:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Comparator comparator = (Integer i1, Integer i2) -> i1.compareTo(i2)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"既然兩個參數都是 Integer 那是不是也可以省略,最後就得到了下面這樣的形式:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Comparator comparator = (i1, i2) -> i1.compareTo(i2)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這就是 lambda 的力量,可以把上面那麼多的代碼濃縮成一行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"lambda 其實就是一段代碼,但也不僅僅是一段代碼,再簡單的 lambda 也會有三部分,參數列表,箭頭和 lambda 主體,上面的 "},{"type":"codeinline","content":[{"type":"text","text":"(i1, i2)"}]},{"type":"text","text":" 就是參數列表, "},{"type":"codeinline","content":[{"type":"text","text":"i1.compareTo(i2)"}]},{"type":"text","text":" 就是 lambda 主體,箭頭把這兩部分隔開了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"lambda 是匿名的,這點和 Java 中的匿名實現類有點像(本質上一樣),而且它是一種函數,不屬於任何類(屬於類的函數稱之爲方法),並且可以作爲參數進行傳遞,而且還很簡潔。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看到這裏,可能就有人猜到函數式接口和 lambda 之間可能有某些關係了,沒錯,我們已經快說到最重要的部分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這之前再來理解一個概念,函數簽名,函數簽名爲可以表示一類函數,如果兩個函數的以下部分相同,就可以說這兩個函數的簽名一致:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"函數參數及其類型"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"返回值及其類型"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可能會拋出的異常"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還有訪問控制符(public等等)"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最關鍵的地方來了,"},{"type":"text","marks":[{"type":"strong"}],"text":"只要 lambda 和函數式接口方法的簽名一致,lambda 表達式就可以作爲參數傳入到以該函數式接口爲參數類型的方法中"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"來看個詳細的例子, "},{"type":"codeinline","content":[{"type":"text","text":"Comparator"}]},{"type":"text","text":" 接口的定義如下:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@FunctionalInterface\npublic interface Comparator {\n int compare(T o1, T o2);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然 Comparator 中方法不止一個,但是抽象方法只有 "},{"type":"codeinline","content":[{"type":"text","text":"compare"}]},{"type":"text","text":" 一個,上面的 lambda 完全可以作爲 compare 方法的實現,實際上,"},{"type":"text","marks":[{"type":"strong"}],"text":"lambda 表達式確實是作爲函數式接口抽象方法的實現,而且,lambda 表達式爲作爲整個函數接口的實例"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到這裏,真相大白,Java 8 的雖然支持了函數式編程,這不代表函數就是 Java中的一等公民了,每一個函數其實還是被包裹成一個對象,對象依然是 Java 中的一等公民。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以簡單來說,只要 lambda 的表達式的參數和返回類型可以與函數式接口中的抽象方法對的上,lambda 就可以作爲該函數式接口的實現進行傳遞。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如上面列舉的幾種函數式接口,其實就是對一些通用函數的抽象,比如 Function 函數式接口如下:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@FunctionalInterface\npublic interface Function {\n R apply(T t);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這種就代表接受一個參數,返回另一個值的函數,只要滿足這個要求的 lambda 表達式都可以作爲 它的實現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再比如 Predicate 接口,代表接受一個參數返回一個布爾值的函數:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@FunctionalInterface\npublic interface Predicate {\n boolean test(T t);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Comsumer 接口表示接受一個參數,什麼都不返回的函數:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"@FunctionalInterface\npublic interface Predicate {\n boolean test(T t);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果這樣理解起來還是有點困難,那就把這些函數式接口理解爲 lambda 表達式的類型。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"類型檢查和類型推斷"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上面我們說到了只要函數式接口抽象方法的函數簽名與 lambda 一致,那麼就可以把 lambda 表達式作爲該函數式接口的實現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面的例子中, lambda 的參數類型也是可以省略的,那麼 Java 是如何判斷 lambda 是否與函數式接口匹配呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果 lambda 表達式中,參數和返回值的類型都省略之後,需要從使用 lambda 的上下文推斷出來。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"03-08-87-%E5%A6%82%E4%BD%95%E7%BC%96%E5%86%99Java8%20%E9%A3%8E%E6%A0%BC%E7%9A%84%E4%BB%A3%E7%A0%81%2059c60dc717f240719b4fdb4382b8b74a/Untitled.png","title":null},"marks":[{"type":"underline"}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/15/157cfb9f21779fc8c9c0e5c418bef203.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"方法引用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本來到這裏應該就很完美了,lambda 夠簡潔,用它寫代碼,可以省略很多無用的樣本代碼,但是 lambda 也不完美,因爲 lambda 表達式的代碼很難複用,而且很多的 lambda 表達式僅僅就是調用了其他的方法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個時候,方法引用就可以派上用場了,比如上面的例子,其實僅僅就是調用了 "},{"type":"codeinline","content":[{"type":"text","text":"Integer.compareTo()"}]},{"type":"text","text":" 方法:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Comparator comparator = (i1, i2) -> i1.compareTo(i2)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還可以簡化成下面的樣子:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Comparator comparator = Integer::compareTo"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用方法引用的時候,要使用 "},{"type":"codeinline","content":[{"type":"text","text":"::"}]},{"type":"text","text":" ,而且任何方法都可以這樣被引用,無論是靜態方法還是實例方法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方法引用可以被認爲是 lambda 的語法糖,使用方法引用可以讓代碼更加簡潔,更直觀,看到方法引用的名稱就能大概知道代碼的邏輯,並且還可以對一些代碼進行復用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"寫出Java8 風格的代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 Java8 之後,很多代碼的寫法應該摒棄,下面列舉一些常見的例子。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"遍歷 List"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 以前:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"for(Integer i : list) {\n System.out.println(i);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 及以後:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"list.forEach(System.out::println);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"forEach 接收 Consumer 類型的函數,而 System.out.println() 剛好就符合要求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"遍歷 Map"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 以前:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"for (Map.Entry entry : map.entrySet()) {\n \n System.out.println(\"Key: \" + entry.getKey() + \", Value:\" + entry.getValue());\n \n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 及以後:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"map.forEach((k, v) -> {System.out.println(\"Key: \"+ k +\", Value: \"+ v)});"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的 forEach 不是接收 Consumer 類型的函數,而是接收 BiConsumer 類的函數,可以用來處理 map 這種包含 key-value 類型的數據,在大多數場景下,內置的函數式接口以及足夠我們使用,只有在一些特殊的場景下才需要自己定製。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏也沒有現成的方法引用,所以就可以使用 lambda 表達式來實現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"執行異步任務"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假如要使用線程池來執行任務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 以前:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 0, TimeUnit.SECONDS, new ArrayBlockingQueue(2000));\n\nexecutor.submit(new Runnable() {\n public void run() {\n System.out.println(\"Thread pool execute\");\n }\n}); "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java8 以後:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 0, TimeUnit.SECONDS, new ArrayBlockingQueue(2000));\n\nexecutor.submit(() ->{\n System.out.println(\"Thread pool execute\");\n});"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也可以使用 lambda 來解決這個問題,Runnable 也是一個函數式接口。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"文 / Rayjun"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文首發於公衆號 Rayjun"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/af/aff0781fde8a41d0b23e298cc79993c7.jpeg?x-oss-process=image/resize,p_80/auto-orient,1","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章