您好,登錄后才能下訂單哦!
Java8中Lambda的特性是什么,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
入門最快就是看demo啦,現在有個需求,讓你在眾多蘋果中挑選出紅色的蘋果
蘋果類
public class Apple { String color; int weight; //省略構造函數,get方法 }
public static List<Apple> filterGreenAppleWithNormal(List<Apple> apples) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if ("red".equals(apple.getColor())) { res.add(apple); } } return res; } //調用 List<Apple> normal = filterGreenAppleWithNormal(apples);
如果再有一個需求說挑選出綠色的蘋果呢,按照這種寫法就需要創建一個新的類,然后僅僅把"red"
修改成"green"
其它都不變,這明顯是不顯示的。所以可以把顏色當成參數傳進去
public static List<Apple> filterGreenAppleWithArg(List<Apple> apples, String color) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if (color.equals(apple.getColor())) { res.add(apple); } } return res; } //調用 List<Apple> arg = filterGreenAppleWithArg(apples, "red");
此時再有一個需求,需要篩選出一定重量或者某個顏色的蘋果,需要怎么辦呢,按照上述想法是把能想到的屬性都堆到方法的參數中。
public static List<Apple> filterWeightOrColorWithArg(List<Apple> apples, String color, int weight, boolean flag) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if (flag && color.equals(apple.getColor()) || !flag && apple.getWeight() > weight) { res.add(apple); } } return res; } //調用 List<Apple> weightOrColor = filterWeightOrColorWithArg(apples, "", 500, false);
可以這樣寫嗎,當然可以解決問題,但是如果有5個屬性呢,6個屬性呢,還有,參數中的flag是什么意思呢。
仔細一想,篩選顏色,篩選重量,這些的本質是在篩選,是一個行為(后面更專業稱謂語),可以把行為抽象成一個接口 。
行為接口
public interface AppleFilter { boolean filter(Apple apple); }
首先需要實現這個接口來具體化行為
篩選紅色蘋果實現類
public class RedFilter implements AppleFilter { @Override public boolean filter(Apple apple) { return "red".equals(apple.getColor()); } }
回到使用
public static List<Apple> filterApples(List<Apple> apples, AppleFilter filter) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if (filter.filter(apple)) { res.add(apple); } } return res; } //調用 List<Apple> behavior = filterApples(apples, new GreenFilter());
這樣看就舒服多了,當有新需求的時候,只需要再添加一個類,比如需求是篩選出重量超200g的蘋果,只需要新建一個篩選類實現上述接口即可。
public class WeightGt200Filter implements AppleFilter { @Override public boolean filter(Apple apple) { return apple.getWeight() > 200; } }
還能怎樣精簡代碼呢?熟悉Java的小伙伴到這里應該就想到了匿名內部類
List<Apple> innerClass = filterApples(apples, new AppleFilter() { @Override public boolean filter(Apple apple) { return "green".equals(apple.getColor()); } });
一般到這一步,比較不錯的IDE就會開始提醒建議了
這就到了我們今天的重點,lambda表達式
List<Apple> lambda = filterApples(apples, apple -> apple.getWeight() > 500);
沒錯,就是這么精簡,不過filterApples
這個方法是不能省略的,但是擴展性相較1,2,簡潔性相較3,4都好了很多
可以把Lamdba表達式理解為簡潔地表示可傳遞的匿名函數的一種形式:它沒有名稱,但它有參數列表、函數主題、返回類型,可能還有一個可以拋出的異常列表
書寫格式: (參數) -> {主體}
正如上面寫法5一樣(apple) -> {apple.getWeight() > 500;}
lambda表達式對參數能夠自動推斷類型,當然也可以顯示書寫類型
沒有return語句,應為已經有隱含了return
lambda中可以有多行語句
使用案例:
() -> {}
() -> "java"
() -> {return "java";}
(int a, int b) -> a * b
() -> {System.out.println("hello"); System.out.println("java");}
使用函數式接口的時候才能使用lambda表達式
所謂函數式接口就是僅僅定義了一個抽象方法,比如一開始把行為抽象成一個AppleFilter
接口,該接口只有一個filter()
方法。注意是只有一個抽象方法,并不是只有一個方法,通俗來說是繼承該接口的類只需要實現一個方法。
最常見的兩個接口是Comparator
和Runnable
后來為了更方便地區分函數式接口,Java新的API中多了一個@FuntionalInterface
,該注解僅僅是表明該類是函數式接口(并不是必須的),如果有該注解的同時聲明了兩個抽象方法,那么將會報錯
java.util.function
下主要有4個常用的函數式接口,Function
,Predicate
,Consumer
,Predicate
,隨便截取其中的一個源碼片段來看,其實也沒啥好看的
對這些函數式接口也是得看接口是如何聲明的,這里就拿Predicate
舉例,該接口主要是對傳進來的對象進行一個處理,然后返回boolean
值。是不是有點熟悉,沒錯,就是和篩選蘋果一樣
predicateDemo
public static List<Apple> predicateDemo(List<Apple> apples, Predicate<Apple> predicate) { List<Apple> res = new ArrayList<>(); for (Apple apple : apples) { if (predicate.test(apple)) { res.add(apple); } } return res; } //調用 List<Apple> predicate = predicateDemo(apples, apple -> "green".equals(apple.getColor()));
其他的也是同理,上才藝
functionDemo
public static List<Integer> functionDemo(List<Integer> nums, Function<Integer, Integer> function) { List<Integer> res = new ArrayList<>(); for (int num : nums) { res.add(function.apply(num)); } return res; } //調用 List<Integer> function = functionDemo(Arrays.asList(1, 8, 7, 3, 9, 2), (num) -> num * 2);
consumerDemo
public static void consumerDemo(List<Integer> list, Consumer<Integer> consumer) { for (int num : list) { consumer.accept(num); } } //調用 consumerDemo(Arrays.asList(1, 5, 6), (num) -> System.out.println(num)); consumerDemo(Arrays.asList(1, 5, 6), System.out::println);
supplierDemo
public static void supplierDemo(List<Integer> nums, Supplier<String> supplier) { StringBuilder sb = new StringBuilder(); for (int num : nums) { sb.append(num).append(supplier.get()); } System.out.println(sb); } //調用 supplierDemo(Arrays.asList(1, 5, 6), ()->"java");
上面的lambda寫法是最精簡的嗎,不,不是的,還有最最最精簡的寫法,那就是利用方法引用
方法引用主要有3類:
指向靜態方法的方法引用
Comparator<Integer> normalComparator = (a, b) -> a.compareTo(b); Comparator<Integer> referenceComparator = Integer::compareTo;
指向任一類型實例方法的方法引用
Function<String, Integer> normalFunction = (str) -> str.length(); Function<String, Integer> referenceFunction = String::length; BiPredicate<List<String>, String> normalPredicate = (strings, str) -> strings.contains(str); BiPredicate<List<String>, String> referencePredicate = List::contains;
指向現有對象的實例方法引用
Apple apple = new Apple(); Supplier<Integer> normal = () -> apple.getWeight(); Supplier<Integer> reference = apple::getWeight;
當然也可以用于構造函數
Supplier<Apple> normalSupplier = () -> new Apple(); Supplier<Apple> referenceSupplier = Apple::new;
看完上述內容,你們掌握Java8中Lambda的特性是什么的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。