1. 程式人生 > 實用技巧 >Java1.8之Lambda表示式、流Stream學習

Java1.8之Lambda表示式、流Stream學習

1、什麼是函數語言程式設計?

答:每個人對函數語言程式設計的理解不盡相同。但其核心是:在思考問題時,使用不可變值和函式,函式對一個值進行處理,對映成另一個值。

2、Java 8的最大變化是引入了Lambda表示式——一種緊湊的、傳遞行為的方式。

答:和使用匿名內部類的另一處不同在於宣告引數的方式。使用匿名內部類時需要顯式地宣告引數型別,而在Lambda表示式中無需指定型別,程式依然可以編譯。這是因為javac根據程式的上下文在後臺推斷出了引數的型別。這意味著如果引數型別不言而明,則無需顯式指定。

  儘管與之前相比,Lambda表示式中的引數需要的樣板程式碼很少,但是Java 8仍然是一種靜態型別語言。為了增加可讀性並遷就我們的習慣,宣告引數時也可以包括型別資訊,而且有時編譯器不一定能根據上下文推斷出引數的型別!

  注意:->符號將引數和Lambda表示式的主體分開。

3、Java8之Lambda的簡單案例使用,如下所示:

 1 package com.demo.main;
 2 
 3 import java.awt.event.ActionListener;
 4 import java.util.function.BinaryOperator;
 5 
 6 public class LambdaMain {
 7 
 8     // 目標型別是指Lambda表示式所在上下文環境的型別。
 9     // 比如,將Lambda表示式賦值給一個區域性變數,或傳遞給一個方法作為引數,區域性變數或方法引數的型別就是Lambda表示式的目標型別。
10 public static void main(String[] args) { 11 // Lambda表示式的不同形式 12 // 1、方式一,Lambda表示式不包含引數,使用空括號()表示沒有引數。 13 // 該Lambda表示式實現了Runnable介面,該介面也只有一個run方法,沒有引數,且返回型別為void。 14 Runnable noArguments = () -> System.out.println("方式一,hello Lambda!!!"); 15 noArguments.run();
16 17 // 2、方式二,Lambda表示式包含且只包含一個引數,可省略引數的括號 18 ActionListener oneArgument = event -> System.out.println("方式二,button clicked !!!"); 19 20 // 3、方式三,Lambda表示式的主體不僅可以是一個表示式,而且也可以是一段程式碼塊,使用大括號({})將程式碼塊括起來 21 Runnable multiStatement = () -> { 22 System.out.println("方式三,hello Lambda first !!!"); 23 System.out.println("方式三,hello Lambda second!!!"); 24 }; 25 multiStatement.run(); 26 27 // 4、方式四,Lambda表示式也可以表示包含多個引數的方法。 28 // 這行程式碼並不是將兩個數字相加,而是建立了一個函式,用來計算兩個數字相加的結果。 29 // 變數add的型別是BinaryOperator<Long>,它不是兩個數字的和,而是將兩個數字相加的那行程式碼。 30 BinaryOperator<Long> add = (x, y) -> x + y; 31 System.out.println("方式四,add : " + add.apply(2L, 3L)); 32 33 // 5、方式五,有時最好也可以顯式宣告引數型別,此時就需要使用小括號將引數括起來,多個引數的情況也是如此 34 BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y; 35 System.out.println("方式五,addExplicit : " + addExplicit.apply(1L, 2L)); 36 37 } 38 39 }

4、Java的函式介面?

答:函式介面是隻有一個抽象方法的介面,用作Lambda表示式的型別。

 1 package com.demo.main;
 2 
 3 public interface LambdaType<T> {
 4 
 5     // 函式介面是隻有一個抽象方法的介面,用作Lambda表示式的型別。
 6     abstract int add(T x,T y);
 7     
 8     public static void main(String[] args) {
 9         LambdaType<Integer> lambdaType =  (x, y) -> x + y;
10         System.out.println(lambdaType.add(1, 2));
11     }
12     
13 }

5、Java8的Lambda要點內容:

答:1)、Lambda表示式是一個匿名方法,將行為像資料一樣進行傳遞。

  2)、Lambda表示式的常見結構: BinaryOperator<Integer> add=(x, y) → x+y。

  3)、函式介面指僅具有單個抽象方法的介面,用來表示Lambda表示式的型別。

6、Stream是用函數語言程式設計方式在集合類上進行復雜操作的工具。

答:1)、Stream裡的一些方法卻略有不同,它們雖是普通的Java方法,但返回的Stream物件卻不是一個新集合,而是建立新集合的配方。

  2)、像filter這樣只描述Stream,最終不產生新集合的方法叫作惰性求值方法,而像count這樣最終會從Stream產生值的方法叫作及早求值方法。

  3)、判斷一個操作是惰性求值還是及早求值很簡單:只需看它的返回值。如果返回值是Stream,那麼是惰性求值;如果返回值是另一個值或為空,那麼就是及早求值。使用這些操作的理想方式就是形成一個惰性求值的鏈,最後用一個及早求值的操作返回想要的結果,這正是它的合理之處。

 1 package com.demo.main;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Iterator;
 5 import java.util.List;
 6 import java.util.stream.Stream;
 7 
 8 public class StramMain {
 9 
10     public static void main(String[] args) {
11         List<String> lists = new ArrayList<String>();
12         lists.add("Java");
13         lists.add("SpringCloud");
14         lists.add("SpringBoot");
15         lists.add("Spring");
16 
17         // 習慣寫法一
18         for (String str : lists) {
19             if (str.contains("Spring")) {
20                 System.out.println("for迴圈:" + str.toString());
21             }
22         }
23         System.out.println();
24 
25         // 習慣寫法二,方法是返回一個控制迭代的Iterator物件
26         Iterator<String> iterator = lists.iterator();
27         while (iterator.hasNext()) {
28             String str = iterator.next();
29             if (str.contains("Spring")) {
30                 System.out.println("while迴圈:" + str.toString());
31             }
32         }
33         System.out.println();
34 
35         // Java8流式寫法,stream()方法的呼叫,返回內部迭代中的相應介面:Stream。
36         long count = lists.stream().filter(list -> {
37             System.out.println("filter是惰性求值方法");
38             return list.contains("Spring");
39         }).count();
40         System.out.println("count及早求值方法: " + count);
41         
42     }
43 
44 }

7、Stream常用的流操作。

答:1)、collect(toList())方法由Stream裡的值生成一個列表,是一個及早求值操作。

  2)、Stream的of方法使用一組初始值生成新的Stream。

 1 package com.demo.main;
 2 
 3 import java.util.List;
 4 import java.util.stream.Collectors;
 5 import java.util.stream.Stream;
 6 
 7 public class StramMain {
 8 
 9     public static void main(String[] args) {
10         // Stream<String> list = Stream.of("Spring", "SpringBoot", "SpringCloud");
11         // List<String> collected = list.collect(Collectors.toList());
12         // 可以縮寫為下面一句
13         List<String> collected = Stream.of("Spring", "SpringBoot", "SpringCloud").collect(Collectors.toList());
14 
15         // 使用流Stream進行遍歷操作,可以直接列印資訊
16         collected.forEach((String str) -> System.out.println(str.toString()));
17         // 省略Lanbda的引數型別
18         collected.forEach(str -> System.out.println(str.toString()));
19     }
20 
21 }

  3)、map如果有一個函式可以將一種型別的值轉換成另外一種型別,map操作就可以使用該函式,將一個流中的值轉換成一個新的流。

 1 package com.demo.main;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 import java.util.stream.Collectors;
 7 import java.util.stream.Stream;
 8 
 9 public class StramMain {
10 
11     public static void main(String[] args) {
12         // 習慣寫法,使用for迴圈將字串轉換為大寫
13         List<String> list = new ArrayList<String>();
14         for (String str : Arrays.asList("Spring", "SpringBoot", "SpringCloud")) {
15             String upperStr = str.toUpperCase();
16             list.add(upperStr);
17         }
18 
19         // Stream流式寫法,使用map操作將字串轉換為大寫形式
20         Stream<String> stream = Stream.of("Spring", "SpringBoot", "SpringCloud").map(str -> str.toUpperCase());
21         List<String> collected = stream.collect(Collectors.toList());
22         collected.forEach(str -> System.out.println(str.toString()));
23         System.out.println();
24 
25         // 一句寫法
26         Stream.of("Spring", "SpringBoot", "SpringCloud")
27                 // 傳給map的Lambda表示式只接受一個String型別的引數,返回一個新的String型別。
28                 .map(str -> str.toUpperCase()) 
29                 // 引數和返回值不必屬於同一種類型,但是Lambda表示式必須是Function介面的一個例項,
30                 // Function介面是隻包含一個引數的普通函式介面。
31                 .collect(Collectors.toList())
32                 .forEach(str -> System.out.println(str.toString()));
33 
34     }
35 
36 }

4)、filter遍歷資料並檢查其中的元素時,可嘗試使用Stream中提供的新方法filter。

 1 package com.demo.main;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Arrays;
 5 import java.util.List;
 6 import java.util.stream.Collectors;
 7 import java.util.stream.Stream;
 8 
 9 public class StramMain {
10 
11     public static void main(String[] args) {
12         // 習慣寫法,使用迴圈遍歷列表,使用條件語句做判斷
13         List<String> list = new ArrayList<String>();
14         for (String str : Arrays.asList("Spring", "SpringBoot", "SpringCloud")) {
15             if (str.startsWith("Spring")) {
16                 list.add(str);
17             }
18         }
19         // 這裡使用流式遍歷
20         list.stream().forEach(str -> System.out.println(str.toString()));
21         System.out.println();
22 
23         // Stream流式寫法,使用迴圈遍歷列表,使用條件語句做判斷
24         Stream<String> stream = Stream.of("Spring", "SpringBoot", "SpringCloud")
25                 .filter(str -> str.startsWith("Spring"));
26         List<String> collected = stream.collect(Collectors.toList());
27         collected.forEach(str -> System.out.println(str.toString()));
28         System.out.println();
29         
30         // Stream一句寫法
31         Stream.of("Spring", "SpringBoot", "SpringCloud")
32                 // 和map很像,filter接受一個函式(函式介面)作為引數,該函式用Lambda表示式表示。
33                 .filter(str -> str.startsWith("Spring"))
34                 .collect(Collectors.toList())
35                 .forEach(str -> System.out.println(str.toString()));
36         
37     }
38 
39 }

5)、flatMap方法可用Stream替換值,然後將多個Stream連線成一個Stream。map操作,它可用一個新的值代替Stream中的值。但有時,如果希望讓map操作有點變化,生成一個新的Stream物件取而代之。使用者通常不希望結果是一連串的流,此時flatMap最能派上用場。

 1 package com.demo.main;
 2 
 3 import java.util.Arrays;
 4 import java.util.List;
 5 import java.util.stream.Collectors;
 6 import java.util.stream.Stream;
 7 
 8 public class StramMain {
 9 
10     public static void main(String[] args) {
11         // 習慣寫法,使用迴圈遍歷列表,使用條件語句做判斷
12 
13         // Stream流式寫法,使用迴圈遍歷列表,使用條件語句做判斷
14         Stream<List<String>> stream = Stream.of(Arrays.asList("Spring"), Arrays.asList("SpringBoot", "SpringCloud"));
15         Stream<String> flatMap = stream.flatMap(list -> list.stream());
16         List<String> list = flatMap.collect(Collectors.toList());
17         list.forEach(str -> System.out.println(str.toString()));
18         System.out.println();
19         
20         // Stream一句寫法
21         Stream.of(Arrays.asList("Spring"), Arrays.asList("SpringBoot", "SpringCloud"))
22                 .flatMap(list2 -> list2.stream())
23                 .collect(Collectors.toList())
24                 .forEach(str -> System.out.println(str.toString()));
25     }
26 
27 }

6)、Stream上常用的操作之一是求最大值和最小值。Stream API中的max和min操作足以解決這一問題。

 1 package com.demo.main;
 2 
 3 import java.util.Arrays;
 4 import java.util.Comparator;
 5 import java.util.List;
 6 import java.util.Optional;
 7 
 8 public class StramMain {
 9 
10     public static void main(String[] args) {
11         List<BookInfo> list = Arrays.asList(new BookInfo("Spring", 100), new BookInfo("SpringBoot", 200),
12                 new BookInfo("SpringCloud", 300));
13 
14         // 習慣寫法,使用迴圈遍歷列表,使用條件語句做判斷
15         BookInfo bookInfo = list.get(0);
16         for (BookInfo book : list) {
17             if (book.getPrice() < bookInfo.getPrice()) {
18                 bookInfo = book;
19             }
20         }
21         System.out.println(bookInfo.toString());
22         System.out.println();
23 
24         // Stream流式寫法,使用迴圈遍歷列表,使用條件語句做判斷
25         Optional<BookInfo> optionalMin = list.stream().min(Comparator.comparing(BookInfo::getPrice));
26         BookInfo bookStreamMin = optionalMin.get();
27         System.out.println(bookStreamMin.toString());
28         System.out.println();
29 
30         // Stream一句寫法
31         // 取出最小值
32         BookInfo bookStreamMin2 = list.stream().min(Comparator.comparing(BookInfo::getPrice)).get();
33         System.out.println(bookStreamMin2.toString());
34         System.out.println();
35 
36         // 取出最大值
37         BookInfo bookStreamMax = list.stream().max(Comparator.comparing(BookInfo::getPrice)).get();
38         System.out.println(bookStreamMax.toString());
39         System.out.println();
40 
41 //        java1.8的雙冒號(::),雙冒號(::)運算子在Java 8中被用作方法引用(method reference),方法引用是與lambda表示式相關的一個重要特性。它提供了一種不執行方法的方法。為此,方法引用需要由相容的函式介面組成的目標型別上下文。
42 //        大致意思是,使用lambda表示式會建立匿名方法, 但有時候需要使用一個lambda表示式只調用一個已經存在的方法(不做其它), 所以這才有了方法引用!
43 
44 //        以下是Java 8中方法引用的一些語法:
45 //        1)、靜態方法引用(static method)語法:classname::methodname 例如:Person::getAge
46 //        2)、物件的例項方法引用語法:instancename::methodname 例如:System.out::println
47 //        3)、物件的超類方法引用語法: super::methodname
48 //        4)、類構造器引用語法: classname::new 例如:ArrayList::new
49 //        5)、陣列構造器引用語法: typename[]::new 例如: String[]:new
50         
51     }
52 
53 }

7)、reduce操作可以實現從一組值中生成一個值。如count、min和max方法,因為常用而被納入標準庫中。事實上,這些方法都是reduce操作。

 1 package com.demo.main;
 2 
 3 import java.util.Arrays;
 4 import java.util.function.BinaryOperator;
 5 import java.util.stream.Stream;
 6 
 7 public class StramMain {
 8 
 9     public static void main(String[] args) {
10         // 習慣寫法,使用指令式程式設計方式求和
11         int sum = 0;
12         for (Integer nums : Arrays.asList(1, 2, 3, 4)) {
13             sum = sum + nums;
14         }
15         System.out.println("sum : " + sum);
16 
17         // Stream流式寫法,使用reduce求和
18         // Lambda表示式的返回值是最新的sum2。
19         // Lambda表示式就是reducer,它執行求和操作,有兩個引數:傳入Stream中的當前元素num2和sum2。將兩個引數相加,sum2是累加器,儲存著當前的累加結果。
20         BinaryOperator<Integer> accumulator = (acc, element) -> acc + element;
21         int count = accumulator.apply(accumulator.apply(accumulator.apply(accumulator.apply(0, 1), 2), 3), 4);
22         System.out.println("count: " + count);
23 
24         // Stream一句寫法
25         Integer sumStream = Stream.of(1, 2, 3, 4).reduce(0, (sum2, num2) -> sum2 + num2);
26         System.out.println("sumStream : " + sumStream);
27 
28     }
29 
30 }

8)、綜合案例,如何根據圖書列表,找出圖書所屬的公司團隊,如下所屬:

  1 package com.demo.main;
  2 
  3 import java.util.HashSet;
  4 import java.util.Set;
  5 import java.util.stream.Collectors;
  6 import java.util.stream.Stream;
  7 
  8 public class StramMain {
  9 
 10     private Set<BookInfo> getAllBookInfos() {
 11         Set<BookInfo> set = new HashSet<BookInfo>();
 12         // 維護圖書集合
 13         set.add(new BookInfo("Spring", "Pivotal-1", 100));
 14         set.add(new BookInfo("SpringBoot", "Pivotal-2", 200));
 15         set.add(new BookInfo("SpringCloud", "Pivotal-3", 300));
 16         return set;
 17     }
 18 
 19     private Set<String> getAllBookNames() {
 20         Set<BookInfo> bookInfos = this.getAllBookInfos();
 21         Set<String> set = new HashSet<String>();
 22         // 遍歷獲取到圖書名稱
 23         for (BookInfo bookInfo : bookInfos) {
 24             set.add(bookInfo.getBookname());
 25         }
 26         return set;
 27     }
 28 
 29     public static void main(String[] args) {
 30         // 習慣寫法
 31 
 32         // Stream流式寫法,找出圖書技術所屬的公司
 33         StramMain stramMain = new StramMain();
 34         // 首先獲取到所有的圖書資訊並過濾到自己想要的圖書資訊
 35         Stream<BookInfo> stream = stramMain.getAllBookInfos().stream()
 36                 .filter(bookInfo -> bookInfo.getBookname().startsWith("Spring"));
 37         // 使用map將技術圖書對映為所屬的公司
 38         Stream<String> streaMap = stream.map(bookInfo -> bookInfo.getTeam());
 39         // 使用collect(Collectors.toList())方法將圖書所屬的公司放入一個列表。
 40         Set<String> collect = streaMap.collect(Collectors.toSet());
 41         // 迴圈遍歷輸出
 42         collect.forEach(bookTeam -> System.out.println(bookTeam.toString()));
 43 
 44         // Stream一句寫法
 45         // filter和map方法都返回Stream物件,因此都屬於惰性求值,而collect方法屬於及早求值。
 46         // List或Set這樣的集合類,只要呼叫List或Set的stream方法就能得到一個Stream物件。
 47         stramMain.getAllBookInfos().stream()
 48                 .filter(bookInfo -> bookInfo.getBookname().startsWith("Spring"))
 49                 // map方法接受一個Lambda表示式,使用該Lambda表示式對Stream上的每個元素做對映,形成一個新的Stream。
 50                 .map(bookInfo -> bookInfo.getTeam())
 51                 .collect(Collectors.toSet())
 52                 .forEach(bookTeam -> System.out.println(bookTeam.toString()));
 53     }
 54 
 55     class BookInfo {
 56         private String bookname;
 57         private String team;
 58         private int price;
 59 
 60         public String getBookname() {
 61             return bookname;
 62         }
 63 
 64         public void setBookname(String bookname) {
 65             this.bookname = bookname;
 66         }
 67 
 68         public String getTeam() {
 69             return team;
 70         }
 71 
 72         public void setTeam(String team) {
 73             this.team = team;
 74         }
 75 
 76         public int getPrice() {
 77             return price;
 78         }
 79 
 80         public void setPrice(int price) {
 81             this.price = price;
 82         }
 83 
 84         @Override
 85         public String toString() {
 86             return "BookInfo [bookname=" + bookname + ", team=" + team + ", price=" + price + "]";
 87         }
 88 
 89         public BookInfo(String bookname, String team, int price) {
 90             super();
 91             this.bookname = bookname;
 92             this.team = team;
 93             this.price = price;
 94         }
 95 
 96         public BookInfo() {
 97             super();
 98         }
 99     }
100 
101 }

8、如何使用Stream流和Lambda重構遺留程式碼。

  1 package com.demo.main;
  2 
  3 import java.util.HashSet;
  4 import java.util.Iterator;
  5 import java.util.Set;
  6 import java.util.stream.Collectors;
  7 
  8 public class StramMain {
  9 
 10     private Set<BookInfo> getAllBookInfos() {
 11         Set<BookInfo> set = new HashSet<BookInfo>();
 12         // 維護圖書集合
 13         set.add(new BookInfo("Spring", "Pivotal-1", 100));
 14         set.add(new BookInfo("SpringBoot", "Pivotal-2", 200));
 15         set.add(new BookInfo("SpringCloud", "Pivotal-3", 300));
 16         return set;
 17     }
 18 
 19     private Set<String> getAllBookNames() {
 20         Set<BookInfo> bookInfos = this.getAllBookInfos();
 21         Set<String> set = new HashSet<String>();
 22         // 遍歷獲取到圖書名稱
 23         for (BookInfo bookInfo : bookInfos) {
 24             set.add(bookInfo.getBookname());
 25         }
 26         return set;
 27     }
 28 
 29     public static void main(String[] args) {
 30         StramMain stramMain = new StramMain();
 31         // 習慣寫法,找出圖書價格大於等於200的圖書資訊列表
 32         Set<BookInfo> seBookInfos = new HashSet<BookInfo>();
 33         for (BookInfo bookInfo : stramMain.getAllBookInfos()) {
 34             // 如果圖書價格大於等於200
 35             if (bookInfo.getPrice() >= 200) {
 36                 seBookInfos.add(bookInfo);
 37             }
 38         }
 39         // 迴圈輸出
 40         Iterator<BookInfo> iterator = seBookInfos.iterator();
 41         while (iterator.hasNext()) {
 42             System.out.println(iterator.next().toString());
 43         }
 44         System.out.println();
 45 
 46         
 47         
 48         // Stream流式寫法,找出圖書價格大於等於200的圖書資訊列表
 49         Set<BookInfo> bookInfoStream = new HashSet<BookInfo>();
 50         stramMain.getAllBookInfos().stream().forEach(bookInfo -> {
 51             if (bookInfo.getPrice() >= 200) {
 52                 bookInfoStream.add(bookInfo);
 53             }
 54         });
 55         bookInfoStream.forEach(bookInfo -> System.out.println(bookInfo.toString()));
 56         System.out.println();
 57 
 58         
 59         
 60         // Stream一句寫法,找出圖書價格大於等於200的圖書資訊列表
 61         Set<BookInfo> bookInfoStream2 = new HashSet<BookInfo>();
 62         stramMain.getAllBookInfos().stream()
 63                 // 找出滿足圖書價格大於200的
 64                 .filter(bookInfo -> bookInfo.getPrice() >= 200)
 65                 // 將滿足條件的圖書列表生成一個新的Stream流
 66                 .map(bookInfo -> bookInfo)
 67                 // 使用迴圈將新生成的流Stream迴圈遍歷到Set集合中
 68                 .forEach(bookInfo -> bookInfoStream2.add(bookInfo));
 69         // 迴圈遍歷輸出
 70         bookInfoStream2.forEach(bookInfo -> System.out.println(bookInfo.toString()));
 71         System.out.println();
 72         
 73         
 74         
 75         // Stream一句寫法,找出圖書價格大於等於200的圖書資訊列表
 76         // 使用collect(Collectors. toList())可以將Stream中的值轉換成一個列表,
 77         // 使用collect(Collectors.toSet())可以將Stream中的值轉換成一個集合。
 78         stramMain.getAllBookInfos().stream()
 79             // 找出滿足圖書價格大於200的
 80             .filter(bookInfo -> bookInfo.getPrice() >= 200)
 81             // 將滿足條件的圖書列表生成一個新的Stream流
 82             .map(bookInfo -> bookInfo)
 83             // 將生成的stream流轉換為set集合
 84             .collect(Collectors.toSet())
 85             .forEach(bookInfo -> System.out.println(bookInfo.toString()));;
 86             
 87     }
 88 
 89     class BookInfo {
 90         private String bookname;
 91         private String team;
 92         private int price;
 93 
 94         public String getBookname() {
 95             return bookname;
 96         }
 97 
 98         public void setBookname(String bookname) {
 99             this.bookname = bookname;
100         }
101 
102         public String getTeam() {
103             return team;
104         }
105 
106         public void setTeam(String team) {
107             this.team = team;
108         }
109 
110         public int getPrice() {
111             return price;
112         }
113 
114         public void setPrice(int price) {
115             this.price = price;
116         }
117 
118         @Override
119         public String toString() {
120             return "BookInfo [bookname=" + bookname + ", team=" + team + ", price=" + price + "]";
121         }
122 
123         public BookInfo(String bookname, String team, int price) {
124             super();
125             this.bookname = bookname;
126             this.team = team;
127             this.price = price;
128         }
129 
130         public BookInfo() {
131             super();
132         }
133     }
134 
135 }

9、高階函式是指接受另外一個函式作為引數,或返回一個函式的函式。高階函式不難辨認:看函式簽名就夠了。如果函式的引數列表裡包含函式介面,或該函式返回一個函式介面,那麼該函式就是高階函式。

 1 /**
 2      * Returns a stream consisting of the results of applying the given
 3      * function to the elements of this stream.
 4      *
 5      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
 6      * operation</a>.
 7      *
 8      * @param <R> The element type of the new stream
 9      * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
10      *               <a href="package-summary.html#Statelessness">stateless</a>
11      *               function to apply to each element
12      * @return the new stream
13      */
14     <R> Stream<R> map(Function<? super T, ? extends R> mapper);

10、Java 8中的另一個變化是引入了預設方法和介面的靜態方法,它改變了人們認識類庫的方式,介面中的方法也可以包含程式碼體了。

答:1)、Java1.8的預設方法,如果子類未實現父介面的方法,則使用父接口裡面的方法,這樣的方法叫作預設方法,在任何介面中,無論函式介面還是非函式介面,都可以使用該方法。

  2)、和類不同,介面沒有成員變數,因此預設方法只能通過呼叫子類的方法來修改子類本身,避免了對子類的實現做出各種假設。

11、Java 8中的預設方法,理解:

答:1)、類勝於介面。如果在繼承鏈中有方法體或抽象的方法宣告,那麼就可以忽略介面中定義的方法。

  2)、子類勝於父類。如果一個介面繼承了另一個介面,且兩個介面都定義了一個預設方法,那麼子類中定義的方法勝出。

  3)、如果上面兩條規則不適用,子類要麼需要實現該方法,要麼將該方法宣告為抽象方法。