JAVA 8 新特性之 為什么要使用 Lambda 表達式?


前序 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 等,都有很好的優化處理。只能感嘆,更新太快,工作太忙,太多東西學不完。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM