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)、如果上面兩條規則不適用,子類要麼需要實現該方法,要麼將該方法宣告為抽象方法。
。