JDK1.8新特性(一) ----Lambda表達式、Stream API、函數式介面、方法引用

来源:https://www.cnblogs.com/rrong/archive/2019/12/23/12088903.html
-Advertisement-
Play Games

jdk1.8新特性知識點: Lambda表達式 Stream API 函數式介面 方法引用和構造器調用 介面中的預設方法和靜態方法 新時間日期API default Lambda表達式 Lambda就是把我們之前一些複雜的代碼更簡單化,比如集合內容的判斷比較/排序,我們之前可以進行遍歷判斷取出我們想 ...


jdk1.8新特性知識點:
  • Lambda表達式
  • Stream API
  • 函數式介面
  • 方法引用和構造器調用
  • 介面中的預設方法和靜態方法
  • 新時間日期API
  • default
  Lambda表達式     Lambda就是把我們之前一些複雜的代碼更簡單化,比如集合內容的判斷比較/排序,我們之前可以進行遍歷判斷取出我們想要的數據或者寫一個匿名內部類compareto等方法進行取出我們想要的數據,實際它們內部也就是進行了一些判斷比較最終返回給了我們想要的結果。     舉例:場景一         現在我們有三個用戶 小明、小紅、小強  他們的年齡分別是16, 18,20,現在我們要把這三個用戶按年齡進行從小到大的排序。         如果按原來的寫法,我們首先想到的應該是 編寫匿名內部類Comparator進行比較然後排序得到我們想要的結果吧,附圖:       舉例:場景二          我們現在要對三個用戶進行篩選,得到年齡是大於16歲的用戶,我們首先想到的應該是進行遍歷集合進行判斷篩選,最後放入到一個新的集合吧,附圖:

 

 現在JDK1.8給我們提供了新的方式Lambda表達式,比上邊的兩個例子編寫的代碼更為簡單更簡介,下麵我們來看一看怎麼比上邊的代碼更簡單。

    場景一:附圖     場景二:附圖

  

  下邊是Lmabda表達式的語法總結:   口訣:左右遇一省括弧,左側推斷類型省   註:當一個介面中存在多個抽象方法時,如果使用lambda表達式,並不能智能匹配對應的抽象方法,因此引入了函數式介面的概念。   先介紹一下Stream API,上邊提到了Stream API,挨著寫,下一個介紹函數式介面。 Stream API:     Stream 是 Java8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執行非常複雜的查找、過濾和映射數據等操作。使用Stream API 對集合數據進行操作,就類似於使用 SQL 執行的資料庫查詢。也可以使用 Stream API 來並行執行操作。簡單來說,Stream API 提供了一種高效且易於使用的處理數據的方式。      註意:1.Stream不會自己存儲元素                2.Stream不會改變源對象,相反他們會返回一個持有新結果集的Stream對象。                3.Stream的操作是延遲執行的,這意味著他們會等到需要結果的時候才執行                4.  只有當作終止操作時,所有的中間操作會一次性的全部執行,稱為“惰性求值”、“延遲載入”                  5. 每一個Stream流只能操作一次,如果第二次操作會報錯stream has already been operated upon or closed       Stream API的執行流程: 直接上代碼:     1.創建流Stream     2.中間操作     3.終止操作
 1 //3.終止操作
 2 /**
 3 * 查找和匹配
 4 * allMatch-檢查是否匹配所有元素
 5 * anyMatch-檢查是否至少匹配一個元素
 6 * noneMatch-檢查是否沒有匹配所有元素
 7 * findFirst-返回第一個元素
 8 * findAny-返回當前流中的任意元素
 9 * count-返迴流中元素的總個數
10 * max-返迴流中最大值
11 * min-返迴流中最小值
12 */
13 //3.1:allMatch檢查是否匹配所有元素是否都成立,都成立返回true 否則返回false
14 Stream<Map<String, Object>> stream2 = maps.stream();
15 boolean a = stream2.allMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
16 System.err.println("結果:"+a); //false
17 //3.2:anyMatch檢查是否至少匹配一個元素,只要有一個成立就返回true
18 Stream<Map<String, Object>> stream3 = maps.stream();
19 boolean b = stream3.anyMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
20 System.err.println("結果:"+b); //true
21 //3.3:noneMatch檢查是否沒有匹配所有元素,因為有成立的所以有匹配的元素,估 不成立
22 Stream<Map<String, Object>> stream4 = maps.stream();
23 boolean c = stream4.noneMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
24 System.err.println("結果:"+c); //false
25 //3.4:findFirst返回第一個元素,按照年齡從小到大排序返回第一個元素
26 Stream<Map<String, Object>> stream5 = maps.stream();
27 Map<String, Object> first = stream5.sorted((x,y) -> Integer.compare(Integer.valueOf(x.get("age")
28 .toString()),Integer.valueOf(y.get("age").toString()))).findFirst().get();
29 System.err.println(first.toString());//{sex=女, name=小紅, age=16}
30 //3.5:findAny-返回當前流中的任意元素
31 Stream<Map<String, Object>> stream6 = maps.stream();
32 Map<String, Object> map = stream6.sorted((x,y) -> Integer.compare(Integer.valueOf(y.get("age")
33 .toString()),Integer.valueOf(x.get("age").toString()))).findAny().get();
34 //多次測試返回固定是這個,感覺因該是內部有一個演算法排序然後返回其中固定某個 {sex=男, name=小明, age=18}
35 //排序之後返回的永遠是第一個
36 System.err.println(map.toString());
37 //3.6:返迴流中元素的總個數
38 Stream<Map<String, Object>> stream7 = maps.stream();
39 long count = stream7.count();
40 System.err.println("長度為:"+count); // 長度為:3
41 //TODO 最大最小就不測試了,自己可以試試

還有功能比較強大的兩個終止操作 reduce和collect 

reduce操作: reduce:(T identity,BinaryOperator)/reduce(BinaryOperator)-可以將流中元素反覆結合起來,得到一個
 1 /**
 2 * reduce :規約操作
 3 * 計算和
 4 * 計算結果作為x,再從數組中取出新值作為y,進行下一步計算
 5 * 結果在加上0 是最後的結果
 6 */
 7 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
 8 Integer count2 = list.stream().reduce(0, (x, y) -> x + y);
 9 System.out.println(count2);
10  
11 Stream<Map<String, Object>> stream8 = maps.stream();
12 //計算總年齡 也可以是浮點型數據 將Integer 換成Double就ok
13 Optional<Integer> op = stream8.map(m -> Integer.valueOf(String.valueOf(m.get("age"))))
14 .reduce(Integer::sum);
15 System.err.println(op.get()); //54    
collect操作:Collect-將流轉換為其他形式,接收一個Collection介面的實現,用於給Stream中元素做彙總的方法,轉換為一個新的集合或者對象
 1 /**
 2 * collect操作:Collect-將流轉換為其他形式,
 3 * 接收一個Collection介面的實現,用於給Stream中元素做彙總的方法
 4 * Collectors.toList()/toSet()
 5 */
 6 Set<Integer> ageList = list.stream().collect(Collectors.toSet());
 7 ageList.stream().forEach(System.out::println);
 8 //取名字,封裝成hashset
 9 HashSet<Integer> hs = list.stream()
10 .collect(Collectors.toCollection(HashSet::new));
11 System.err.println(hs.toString());

函數式介面:

        函數式介面的提出是為了給Lambda表達式的使用提供更好的支持。
什麼是函數式介面?         簡單來說就是只定義了一個抽象方法的介面(Object類的public方法除外),就是函數式介面,並且還提供了註解:@FunctionalInterface 函數式介面(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的介面。 函數式介面可以被隱式轉換為 lambda 表達式。 Lambda 表達式和方法引用(實際上也可認為是Lambda表達式)上。 如定義了一個函數式介面如下:
1 @FunctionalInterfaceinterface GreetingService
2 {
3         void sayMessage(String message);
4 }
5  
6 // 那麼就可以使用Lambda表達式來表示該介面的一個實現(註:JAVA 8 之前一般是用匿名類實現的):
7 GreetingService greetService1 = message -> System.out.println("Hello " + message);
常見的四大函數式介面有:         Consumer 《T》:消費型介面,有參無返回值         Supplier 《T》:供給型介面,無參有返回值         Function 《T,R》:函數式介面,有參有返回值         Predicate《T》:斷言型介面,有參有返回值,返回值是boolean類型
 1 /**
 2 * @MethodName: functionInterface
 3 * @Description: 四大函數式介面練習
 4 * @param
 5 * @return
 6 * @author rongrong
 7 * @date 2019-12-23
 8 */
 9 public void functionInterface(){
10 /**
11 * 1.Consumer 《T》:消費型介面,有參無返回值
12 * 列印:
13 * 222222
14 * hello
15 */
16 changeStr("hello",(str) -> System.err.println(str));
17  
18 /**
19 * 2.Supplier 《T》:供給型介面,無參有返回值
20 * 列印:
21 * 111111
22 * str
23 */
24 String value = getValue(() -> "str");
25 System.err.println(value);
26  
27 /**
28 * 3. Function 《T,R》::函數式介面,有參有返回值
29 * 列印:
30 * 333333
31 * 20000
32 */
33 Long aLong = changeNum(100L, x -> x * 200);
34 System.err.println(aLong);
35 /**
36 * Predicate《T》: 斷言型介面,有參有返回值,返回值是boolean類型
37 * 列印:
38 * true
39 */
40 boolean rongrong = changeBoolean("rongrong", x -> x.equals("rongrong"));
41 System.err.println(rongrong);
42  
43 }
44  
45 /**
46 * Consumer<T> 消費型介面
47 * @param str
48 * @param con
49 */
50 public void changeStr(String str, Consumer<String> con){
51 System.err.println("222222");
52 con.accept(str);
53 }
54  
55 /**
56 * Supplier<T> 供給型介面
57 * @param sup
58 * @return
59 */
60 public String getValue(Supplier<String> sup){
61 System.err.println("111111");
62 return sup.get();
63 }
64  
65 /**
66 * Function<T,R> 函數式介面
67 * @param num
68 * @param fun
69 * @return
70 */
71 public Long changeNum(Long num, Function<Long, Long> fun){
72 System.err.println("333333");
73 return fun.apply(num);
74 }
75  
76 /**
77 * Predicate<T> 斷言型介面
78 * @param str
79 * @param pre
80 * @return
81 */
82 public boolean changeBoolean(String str, Predicate<String> pre){
83 return pre.test(str);
84 }

在四大核心函數式介面基礎上,還提供了諸如BiFunction、BinaryOperation、toIntFunction等擴展的函數式介面,都是在這四種函數式介面上擴展而來的,不做贅述。

總結:函數式介面的提出是為了讓我們更加方便的使用lambda表達式,不需要自己再手動創建一個函數式介面,直接拿來用就好了,詳細介面描述在下邊。     方法引用:         若lambda體中的內容有方法已經實現了,那麼可以使用“方法引用”也可以理解為方法引用是lambda表達式的另外一種表現形式並且其語法比lambda表達式更加簡單 (a) 方法引用     三種表現形式:         1. 對象:實例方法名         2. 類::靜態方法名         3. 類::實例方法名 (lambda參數列表中第一個參數是實例方法的調用 者,第二個參數是實例方法的參數時可用)
 1 /**
 2 *註意:
 3 * 1.lambda體中調用方法的參數列表與返回值類型,要與函數式介面中抽象方法的函數列表和返回值類型保持一致!
 4 * 2.若lambda參數列表中的第一個參數是實例方法的調用者,而第二個參數是實例方法的參數時,可以使用ClassName::method
 5 * 下邊寫的例子 上邊是不簡化時的寫法,下邊的是對應的簡化寫法,就是方法引用
 6 */
 7  
 8 //100
 9 //200
10 Consumer<Integer> con = (x) -> System.out.println(x);
11 con.accept(100);
12 // 方法引用-對象::實例方法
13 Consumer<Integer> con2 = System.out::println;
14 con2.accept(200);
15  
16 // 方法引用-類名::靜態方法名
17 BiFunction<Integer, Integer, Integer> biFun = (x, y) -> Integer.compare(x, y);
18 Integer apply = biFun.apply(100, 200);
19 BiFunction<Integer, Integer, Integer> biFun2 = Integer::compare;
20 Integer result = biFun2.apply(100, 200);
21 //-1:-1
22 System.err.println(apply + ":" + result);
23  
24 // 方法引用-類名::實例方法名
25 BiFunction<String, String, Boolean> fun1 = (str1, str2) -> str1.equals(str2);
26 Boolean apply1 = fun1.apply("rong", "rong");
27 BiFunction<String, String, Boolean> fun2 = String::equals;
28 Boolean result2 = fun2.apply("hello", "world");
29 //true:false
30 System.out.println(apply1 + ":" + result2);
(b)構造器引用          格式:ClassName::new
 1 // 構造方法引用 類名::new
 2 Supplier<String> sup = () -> new String();
 3 System.out.println(sup.get());
 4 Supplier<String> sup2 = String::new;
 5 System.out.println(sup2.get());
 6  
 7 // 構造方法引用 類名::new (帶一個參數)
 8 //x 代表是傳進去的參數,也就是泛型中的Integer類型
 9 //new String(...) 代表泛型中的String類型
10 Function<Integer, String> fun = x -> new String(String.valueOf(x));
11 System.err.println(fun.apply(100));
12 Function<String, String> fun3 = String::new;
13 System.out.println(fun3.apply("100"));
(c)數組引用 格式:Type[]::new
1 // 數組引用
2 Function<Integer, String[]> arrayFun = (x) -> new String[x];
3 Function<Integer, String[]> arrayFun2 = String[]::new;
4 //給String數組設置了兩個長度。但是值是null
5 String[] strArray = arrayFun2.apply(2);
6 Arrays.stream(strArray).forEach(System.out::println);
 
序號 介面 & 描述
1 BiConsumer<T,U> 代表了一個接受兩個輸入參數的操作,並且不返回任何結果
2 BiFunction<T,U,R> 代表了一個接受兩個輸入參數的方法,並且返回一個結果
3 BinaryOperator<T> 代表了一個作用於於兩個同類型操作符的操作,並且返回了操作符同類型的結果
4 BiPredicate<T,U> 代表了一個兩個參數的boolean值方法
5 BooleanSupplier 代表了boolean值結果的提供方
6 Consumer<T> 代表了接受一個輸入參數並且無返回的操作
7 DoubleBinaryOperator 代表了作用於兩個double值操作符的操作,並且返回了一個double值的結果。
8 DoubleConsumer 代表一個接受double值參數的操作,並且不返回結果。
9 DoubleFunction<R> 代表接受一個double值參數的方法,並且返回結果
10 DoublePredicate 代表一個擁有double值參數的boolean值方法
11 DoubleSupplier 代表一個double值結構的提供方
12 DoubleToIntFunction 接受一個double類型輸入,返回一個int類型結果。
13 DoubleToLongFunction 接受一個double類型輸入,返回一個long類型結果
14 DoubleUnaryOperator 接受一個參數同為類型double,返回值類型也為double 。
15 Function<T,R> 接受一個輸入參數,返回一個結果。
16 IntBinaryOperator 接受兩個參數同為類型int,返回值類型也為int 。
17 IntConsumer 接受一個int類型的輸入參數,無返回值 。
18 IntFunction<R> 接受一個int類型輸入參數,返回一個結果 。
19 IntPredicate :接受一個int輸入參數,返回一個布爾值的結果。
20 IntSupplier 無參數,返回一個int類型結果。
21 IntToDoubleFunction 接受一個int類型輸入,返回一個double類型結果 。
22 IntToLongFunction 接受一個int類型輸入,返回一個long類型結果。
23 IntUnaryOperator 接受一個參數同為類型int,返回值類型也為int 。
24 LongBinaryOperator 接受兩個參數同為類型long,返回值類型也為long。
25 LongConsumer 接受一個long類型的輸入參數,無返回值。
26 LongFunction<R> 接受一個long類型輸入參數,返回一個結果。
27 LongPredicate R接受一個long輸入參數,返回一個布爾值類型結果。
28 LongSupplier 無參數,返回一個結果long類型的值。
29 LongToDoubleFunction 接受一個long類型輸入,返回一個double類型結果。
30 LongToIntFunction 接受一個long類型輸入,返回一個int類型結果。
31 LongUnaryOperator 接受一個參數同為類型long,返回值類型也為long。
32 ObjDoubleConsumer<T> 接受一個object類型和一個double類型的輸入參數,無返回值。
33 ObjIntConsumer<T> 接受一個object類型和一個int類型的輸入參數,無返回值。
34 ObjLongConsumer<T> 接受一個object類型和一個long類型的輸入參數,無返回值。
35 Predicate<T> 接受一個輸入參數,返回一個布爾值結果。
36 Supplier<T> 無參數,返回一個結果。
37 ToDoubleBiFunction<T,U> 接受兩個輸入參數,返回一個double類型結果
38 ToDoubleFunction<T> 接受一個輸入參數,返回一個double類型結果
39 ToIntBiFunction<T,U> 接受兩個輸入參數,返回一個int類型結果。
40 ToIntFunction<T> 接受一個輸入參數,返回一個int類型結果。
41 ToLongBiFunction<T,U> 接受兩個輸入參數,返回一個long類型結果。
42 ToLongFunction<T> 接受一個輸入參數,返回一個long類型結果。
43 UnaryOperator<T> 接受一個參數為類型T,返回值類型也為T。
                       
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • package main import ( "fmt" "reflect" ) type BinaryNode struct { Data interface{} //數據 lChild *BinaryNode //左子樹 rChild *BinaryNode //右子樹 } //創建二叉樹 fun... ...
  • 1. 冒泡排序(bubble sort)的基本思想:比較相鄰兩個 元素的關鍵字值,如果反序,則交換 2. 快速排序 快速排序(quick sort)是一種分區交換排序演算法. 它的基本思想:在數據序列中選擇一個值作為比較的基準值, 每趟從數據序列的兩端開始交替進行,將小於基準值的元素交換到序列前端,將 ...
  • 場景 Dubbo簡介與基本概念: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103555224 Dubbo環境搭建-ZooKeeper註冊中心: https://blog.csdn.net/BADAO_LIUMANG_QIZH ...
  • “==”操作符 基本類型比較值:判斷兩個變數的值相等。 引用類型比較引用(是否指向同一個對象):只有指向同一個對象時才相等。 用“==”進行比較時,兩邊的數據類型必須相容(可自動轉換的基本數據類型除外)。 equals() 所有類都繼承了Object,也就是獲得了equals()方法,還可以重寫。 ...
  • 實現文件分離 1.頭文件中不要使用using namespace,由於c++編譯的特性,由於初學還沒深入瞭解,不做具體編譯的解釋 2.由於沒有了命名空間,所以string定義要寫成std::string 3.main.cpp中引入staff.cpp,staff.cpp中引入staff.h main. ...
  • 對java對象的強制類型轉換稱為造型 從子類到父類的類型轉換可以自動進行; 從父類到子類的類型轉換必須通過造型(強制類型轉換)實現; 無繼承關係的引用類型間的轉換是非法的; ...
  • object類是所有java類的根父類 如果在類的聲明中未使用extends關鍵字指明父類,則預設父類為object類。 object類中的主要方法 public boolean equals(Object obj) 對象比較 public int hashCode() 取得hash碼 public ...
  • HoJe男孩子你要加油阿 準備材料微信支付需要的參數統一下單二維碼回調介面用到的工具類 . 準備材料 首先肯定是要有微信的開發文檔開發文檔地址再然後就是一些必的參數註意:回調地址非同步接收微信支付結果通知的回調地址,通知url必須為外網可訪問的url,不能攜帶參數。 再然後就是微信的SDK . 微信支 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...