前序 Lambda 表達式 介紹:
1:在 java 8 中引入了一個新的操作符"->",該操作符稱為箭頭操作符或Lambda操作符。 2:箭頭操作符將Lambda表達式才分為兩部分。 左側:Lambda 表達式的參數列表。 右側:Lambda 體,即對接口的實現。
3:學習 Lambda 表達式先 應該了解一個知識點 ”函數式接口“,使用 Lambda 表達式必須要有“函數式接口”支持。
了解地址:https://www.runoob.com/java/java8-functional-interfaces.html
@FunctionalInterface 注解:
該注解能夠強制要求接口為 ”函數式接口“
代碼演示:不用 @FunctionalInterface 注解:
package com.test.factory; public interface FunctionalInterfaceTest { /** * 獲取 用戶姓名 * @return */ String getName(); /** * 獲取用戶年齡 */ void getage(); }
代碼演示:使用 @FunctionalInterface 注解: 存在了多個 抽象方法,所以指定 該注解 會報錯,意思就是該接口必須指定成 “函數式接口”。
若接口中存在 一個以上的抽象方法,就不能稱之為 ”函數式接口", @FunctionalInterface 可以強制要求該類必須為“函數式接口”。
若要定義 “函數式接口” 只需要保存一個 抽象方法 即可。用不用 @FunctionalInterface 注解都不重要
如下圖:只保留一個 抽象方法,就是一個合法的 “函數式接口”。
經典的函數式接口:Runnable
學習過多線程的朋友應該很清楚這個 接口。
“函數式接口" 定義總結:
“函數式接口” 的含義:
核心:就是為了支持 Lambda 表達式 所定義的接口,
定義:“函數式接口” 必須保證 該接口 只有一個 抽象方法。
@FunctionalInterface注解:可以強制要求 該接口必須為 “函數式接口”。
Lambda 表達式 優點:
Lambda 表達式 只有一個優點:省,簡化重復代碼,只保留核心代碼。使代碼邏輯更加清晰。
Lambda 表達式 代碼演示:
多說無益,看不到效果,即便說的天花爛醉又是如何?接下來統過一個 小小的案例,見識一下 Lambda 表達式 的 魅力之處。
需求:有一組員工信息存放到一個集合中,並且按照不同需求,來獲取員工信息。
聲明:
案例展示中的案例 來源於 https://www.bilibili.com/video/av71563078?p=2 ,代碼是我學習時按照視頻課程內容講解敲的(主要是想思考Lambda 的 演進過程,實際工作中用過Lambda,只是不知道是Lambda表達式,當時很傻的以為是idea 支持這么做)。
記錄博客,只是單純的記錄一下學習筆記,看別人的代碼還不如自己動手敲一遍,找個差不多的案例。如有侵權,請聯系我,我會主動刪除。
對於內容思考有所不對的地方請指明出來,一起學習,一起進步。
再次聲明:以下代碼只是我學習時,練手代碼,對於質量我不敢保證,真正想學習 Lambda 的朋友,可以看視頻教程或其他高質量的博客。
案例展示:
- 員工實體對象
/** * @author Administrator * @version 1.0 * @describe 員工信息 POJO * @date 2019/12/20 19:52 */ public class StaffModel { /** * 姓名 */ private String name; /** * 年齡 */ private int age; /** * 性別 */ private char gender; /** * 薪資 */ private double salary; get()... set()... toString()... }
- 員工信息集:以下案例會都用這些數據。
public class LambdaTest { private static List<StaffModel> staffModelList=new ArrayList<>(); static { staffModelList.add(new StaffModel("張三",25,'男',5000)); staffModelList.add(new StaffModel("村花",25,'女',5500)); staffModelList.add(new StaffModel("李飛飛",21,'男',2000)); staffModelList.add(new StaffModel("牛妞妞",30,'女',10000)); staffModelList.add(new StaffModel("王曉非",24,'男',6000)); } }
傳統方式:
- 案例一:普通的獲取 工作大於或等於5000的 員工信息
/** * 需求一:獲取員工中 工資大於或五千的 員工信息 * @return */ public static List<StaffModel> salaryFilter(List<StaffModel> list){ List<StaffModel> staffModelList=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (list.get(i).getSalary() >= 5000) { staffModelList.add(list.get(i)); } } return staffModelList; } /** * 測試 * @param args */ public static void main(String[] args) { System.out.println(salaryFilter(staffModelArrayList)); } // 結果 [StaffModel{name='張三', age=25, gender=男, salary=5000.0},
StaffModel{name='村花', age=25, gender=女, salary=5500.0},
StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0},
StaffModel{name='王曉非', age=24, gender=男, salary=6000.0}] -
案例二:獲取 男性的員工信息
/** * 需求二:獲取男性員工信息 * @return */ public static List<StaffModel> genderFilter(List<StaffModel> list){ List<StaffModel> staffModelList=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (list.get(i).getGender() == '男') { staffModelList.add(list.get(i)); } } return staffModelList; } /** * 測試 * @param args */ public static void main(String[] args) { System.out.println(genderFilter(staffModelArrayList)); } //測試 [StaffModel{name='張三', age=25, gender=男, salary=5000.0},
StaffModel{name='李飛飛', age=21, gender=男, salary=2000.0},
StaffModel{name='王曉非', age=24, gender=男, salary=6000.0}]
- 整體代碼展示:
/** * 需求一:獲取員工中 工資大於或五千的 員工信息 * @return */ public static List<StaffModel> salaryFilter(List<StaffModel> list){ List<StaffModel> staffModelList=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (list.get(i).getSalary() >= 5000) { staffModelList.add(list.get(i)); } } return staffModelList; } /** * 需求二:獲取男性員工信息 * @return */ public static List<StaffModel> genderFilter(List<StaffModel> list){ List<StaffModel> staffModelList=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (list.get(i).getGender() == '男') { staffModelList.add(list.get(i)); } } return staffModelList; }
- 總結與思考
在傳統方式中(如上例),面對不同的需求,我們需要 編寫不同的方法(genderFilter()、genderFilter()),來實現,但是核心代碼只有一句,
if (不同需求的條件(核心代碼)) { staffModelList.add(list.get(i)); }
若我們還有一個需求,獲取年齡在25或25以上的員工信息,在傳統方式中,我們無非就是再創建一個方法 copy 上面案例代碼,更改 if(list.get(i).getAge()>=25) 這一句代碼而已。
因為這一句代碼,我們需要寫很多重復性代碼,如需求一 和 需求二,其實我們要改變的只有 if 條件判斷而已。其他代碼都不會做任何改動。
對於這樣的代碼,我們需要進行優化。只留核心,剔除其他。
優化方式一:設計模式
- 定義一個接口,由子類實現,完成過濾
/** * 過濾 策略 接口 * @author Administrator * @param <T> */ public interface FilterStrategy<T> { boolean filter(T t); }
- 創建一個子類,實現其接口,過濾規則由子類來定義
/** * 薪資過濾, * 案例:過濾工資大於或等於 5000 的 員工 * @author Administrator */ public class SalaryFilter implements FilterStrategy<StaffModel> { @Override public boolean filter(StaffModel staffModel) { return staffModel.getSalary()>=5000; } }
-
具體實現 案例一:普通的獲取 工作大於或等於5000的 員工信息
/** * 員工過濾 * @param list 員工信息集 * @param strategy 過濾策略 * @return */ public static List<StaffModel> staffFilter(List<StaffModel> list,FilterStrategy<StaffModel> strategy){ List<StaffModel> staffModelList=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (strategy.filter(list.get(i))) { staffModelList.add(list.get(i)); } } return staffModelList; } /** * 測試 * @param args */ public static void main(String[] args) { //采用 薪資過濾策略 List<StaffModel> staffModelList=staffFilter(staffModelArrayList,new SalaryFilter()); System.out.println(staffModelList); } // 測試結果 [StaffModel{name='張三', age=25, gender=男, salary=5000.0}, StaffModel{name='村花', age=25, gender=女, salary=5500.0}, StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0}, StaffModel{name='王曉非', age=24, gender=男, salary=6000.0}]
- 具體實現 案例二: 獲取 男性的員工信息
/** * 案例二:獲取員工中所有男性員工信息 * @author Administrator */ public class GenderFilter implements FilterStrategy<StaffModel> { @Override public boolean filter(StaffModel staffModel) { return staffModel.getGender()=='男'; } } /** * 測試 * @param args */ public static void main(String[] args) { //采用 薪資過濾策略 List<StaffModel> staffModelList=staffFilter(staffModelArrayList,new GenderFilter()); System.out.println(staffModelList); } // 運行結果 [StaffModel{name='張三', age=25, gender=男, salary=5000.0},
StaffModel{name='李飛飛', age=21, gender=男, salary=2000.0},
StaffModel{name='王曉非', age=24, gender=男, salary=6000.0}] - 總結與思考:
這里采用的設計模式 為策略設計模式,與之前按照不同的需求來創建方法的傳統方式相比,設計模式減少了冗余代碼量,方法只有一個方法,只是需要按照不同的需求創建策略就行了。減少了冗余代碼。只關注於核心。符合了OCP 原則。
- 案例二展示:
1:新建了一個過濾規則:性別過濾規則 2:方法依舊是那個方法,只是main 方法 中的過濾規則變了。
/** * 案例二:獲取員工中所有男性員工信息 * @author Administrator */ public class GenderFilter implements FilterStrategy<StaffModel> { @Override public boolean filter(StaffModel staffModel) { return staffModel.getGender()=='男'; } } /** * 員工過濾 * @param list 員工信息集 * @param strategy 過濾策略 * @return */ public static List<StaffModel> staffFilter(List<StaffModel> list,FilterStrategy<StaffModel> strategy){ List<StaffModel> staffModelList=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (strategy.filter(list.get(i))) { staffModelList.add(list.get(i)); } } return staffModelList; } /** * 測試 * @param args */ public static void main(String[] args) { //采用 性別過濾策略 List<StaffModel> staffModelList=staffFilter(staffModelArrayList,new GenderFilter()); System.out.println(staffModelList); }
優化方式二:匿名內部類
- 上一步方式的缺點:
上一步的優化方式是采用策略模式,那么他有什么缺點呢?設計模式肯定是沒有缺點,這是再這里的案例中比較浪費,只要凡是增加一個需求,就必須創建一個類,編寫相對應的過濾策略。之所以說浪費,是因為類代碼少,又不得不創建一個新類(心累),顯得很浪費而已。
所以這里又有一種優化方式,匿名內部類。 - 代碼展示:
/** * 員工過濾 * @param list 員工信息集 * @param strategy 過濾策略 * @return */ public static List<StaffModel> staffFilter(List<StaffModel> list,FilterStrategy<StaffModel> strategy){ List<StaffModel> staffModelList=new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (strategy.filter(list.get(i))) { staffModelList.add(list.get(i)); } } return staffModelList; } /** * 測試 采用匿名內部類方式 進行過濾,過濾 年齡在 22 以上的員工信息 * @param args */ public static void main(String[] args) { List<StaffModel> staffModelList = staffFilter(staffModelArrayList, new FilterStrategy<StaffModel>() { @Override public boolean filter(StaffModel staffModel) { return staffModel.getAge()>22; } }); System.out.println(staffModelList); } //運行結果 [StaffModel{name='張三', age=25, gender=男, salary=5000.0},
StaffModel{name='村花', age=25, gender=女, salary=5500.0},
StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0},
StaffModel{name='王曉非', age=24, gender=男, salary=6000.0}] - 總結與思考
對於上一種優化方式,不必再創建一個新的過濾器類。相對較而言,代碼更少,更清晰。
優化方式三:Lambda 表達式
- 如果你的是 Idea 你會發現當你寫 匿名內部類的時候,他已經提示你可以進行優化了
- 優化后的效果:代碼已經縮短成了 兩句代碼 標志為 橙色 的就是我們需要的核心代碼。
/** * 測試 * @param args */ public static void main(String[] args) { List<StaffModel> staffModelList = staffFilter(staffModelArrayList, staffModel -> staffModel.getAge()>22); System.out.println(staffModelList); } // 運行結果 [StaffModel{name='張三', age=25, gender=男, salary=5000.0},
StaffModel{name='村花', age=25, gender=女, salary=5500.0},
StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0},
StaffModel{name='王曉非', age=24, gender=男, salary=6000.0}] - 再來一個需求,獲取名稱為 “張三” 的員工信息
/** * 測試 * @param args */ public static void main(String[] args) { List<StaffModel> staffModelList = staffFilter(staffModelArrayList, staffModel -> staffModel.getName().equals("張三")); System.out.println(staffModelList); } //運行結果 [StaffModel{name='張三', age=25, gender=男, salary=5000.0}]
- 總結與思考
Lambda 表達式 優化了我們代碼,使我們的代碼看起來,更加簡單和清晰。Lambda 表達式 的支持,需要 jdk1.8 以上(聽說 jdk 已經 都11了)而我實際工作中用的還是 jdk8,對jdk 8的特性了解甚少。慚愧
優化方式四:Steam ApI
- 應該是 jdk8 新的特性,不是很了解,直接代碼展示吧
public class LambdaTest { private static List<StaffModel> staffModelArrayList=new ArrayList<>(); static { staffModelArrayList.add(new StaffModel("張三",25,'男',5000)); staffModelArrayList.add(new StaffModel("村花",25,'女',5500)); staffModelArrayList.add(new StaffModel("李飛飛",21,'男',2000)); staffModelArrayList.add(new StaffModel("牛妞妞",30,'女',10000)); staffModelArrayList.add(new StaffModel("王曉非",24,'男',6000)); } /** * 測試 * @param args */ public static void main(String[] args) { staffModelArrayList .stream() .filter((e) -> e.getAge()>22) //過濾 年齡 大於 22 的員工信息 .forEach(System.out::println); // 進行打印 類似 System.out.println } } // 運行結果 StaffModel{name='張三', age=25, gender=男, salary=5000.0} StaffModel{name='村花', age=25, gender=女, salary=5500.0} StaffModel{name='牛妞妞', age=30, gender=女, salary=10000.0} StaffModel{name='王曉非', age=24, gender=男, salary=6000.0}
- 除此之外還可以進行 向 sql 那樣 分頁(limit)
/** * 測試 * @param args */ public static void main(String[] args) { staffModelArrayList .stream() .filter((e) -> e.getAge()>22) //獲取前兩條數據 .limit(2) .forEach(System.out::println); } //運行結果 StaffModel{name='張三', age=25, gender=男, salary=5000.0} StaffModel{name='村花', age=25, gender=女, salary=5500.0}
- 總結與思考
除此之外,還有hash 等,都有很好的優化處理。只能感嘆,更新太快,工作太忙,太多東西學不完。