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

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等擴展的函數式接口,都是在這四種函數式接口上擴展而來的,不作贅述。app

總結:函數式接口的提出是爲了讓咱們更加方便的使用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。
相關文章
相關標籤/搜索