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