lambda表達式的學習

Lambda表達式

為什麼使用lambda表達式

Lambda表達式可以簡化我們的程式碼,使我們只需要關注主要的程式碼就可以。

//測試用的實體類

public class Employee {

    private String name;
    private Integer age;
    private double salary;

    public Employee() {
    }

    public Employee(String name, Integer age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
}
//定義要操作的集合數據
    List<Employee> employees = Arrays.asList(

            new Employee("張三",18,3000),
            new Employee("李四",18,3000),
            new Employee("張三",45,8700),
            new Employee("王五",26,4500),
            new Employee("麻子",30,2700),
            new Employee("田七",15,200)

    );

//需求找出年齡大於20的員工


---------------最常規的操作--------
    
//過濾方法
public List<Employee> filterEmployee(List<Employee> employees){

    ArrayList<Employee> list = new ArrayList<>();
    for (Employee employee : employees) {
        if(employee.getAge() > 20){
            list.add(employee);
        }
    }
    return list;
}

//測試方法
@Test
public void test1(){
    List<Employee> employees = filterEmployee(this.employees);

    for (Employee employee : employees) {
        System.out.println(employee);
    }
}

//Employee{name='張三', age=45, salary=8700.0}
//Employee{name='王五', age=26, salary=4500.0}
//Employee{name='麻子', age=30, salary=2700.0}

-------------第二種寫法----------(策略模式)
    
1、先定義一個介面
    
public interface MyPredicate<T> {

    public boolean test(T t);

}

2、定義過濾類實現我們定義的介面
  public class FilterEmployeeByAge implements MyPredicate<Employee>{
    @Override
    public boolean test(Employee employee) {

        return employee.getAge()>20;
    }
}  

3、同樣定義過濾方法
  //過濾方法
public List<Employee> filterEmployee(List<Employee> employees, Mypredicatre<Employee> mp){

    ArrayList<Employee> list = new ArrayList<>();
    for (Employee employee : employees) {
        if(mp.test){
            list.add(employee);
        }
    }
    return list;
}

4、測試方法
   
    @Test
    public void test2(){
        List<Employee> employees = filterEmployee(this.employees, new FilterEmployeeByAge());

        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
    
//Employee{name='張三', age=45, salary=8700.0}
//Employee{name='王五', age=26, salary=4500.0}
//Employee{name='麻子', age=30, salary=2700.0}

-----------上面的方法每過濾不同的條件都要實現一個介面,不是很友好---------我們可以使用匿名內部類
   
        @Test
    public void test3(){
        List<Employee> employees = filterEmployee(this.employees, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getAge() > 20;
            }
        });
    
-----------------匿名內部類可以使用lambda表達式簡化----------
    @Test
    public void test4(){
        List<Employee> employees = filterEmployee(this.employees, (e) -> e.getAge() > 20);

        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }

lambda表達式需要函數式介面支援。

函數式介面:只有一個方法的介面,可以用註解@FunctionalInterface修飾介面

語法格式:

  • 無參數,無返回值 ()->System.out.println(“hello word”)
    @Test
    public void test(){
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        };
        //------------------lambda-----------------------------
            Runnable r1 = ()-> System.out.println("hello world");
    }
  • 有一個參數,無返回值 (x)-> System.out.println(x) (有一個參數小括弧可以不寫)
    @Test
    public void test2(){
        Consumer<String> con = (x)-> System.out.println(x);
        //Consumer<String> con = x-> System.out.println(x);
        con.accept("hello world");
    }
  • 有兩個參數,且有返回值 (有多條語句,必須使用{})
    @Test
    public void test3(){
        Comparator<Integer> com = (x,y)->{
            System.out.println("函數式介面");
            return Integer.compare(x,y);
        };
    }
  • 有兩個參數,且有返回值,語句只有一條 (return 和{} 可以省略)
    @Test
    public void test4(){
        Comparator<Integer> com = (x,y)->Integer.compare(x,y);
    }
  • lambda參數列表的數據類型可以省略不用寫(類型推斷)(要寫都得寫,不能寫一個,一個不寫)

java8中4大核心介面

Consumer : 消費型介面

​ void accept(T t);

    @Test
    public void test4(){
        happy(1000,(m) -> System.out.println("你消費了:"+m+"元"));
    }


    public void happy(double money, Consumer<Double> con){
        con.accept(money);
    }

Supplier : 供給型介面

​ T get();

    @Test
		//獲取隨機數
    public void test5() {
        List<Integer> numList = getNumList(5, () -> (int) (Math.random() * 10));
        System.out.println(numList.toString());
    }
		//產生整數集合
    public List<Integer> getNumList(int num, Supplier<Integer> sup) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }
        return list;
    }

Function<T,R>: 函數式介面

​ R apply(T t);

    @Test
    public void test6(){
        String str = strHandle("hello world", (s) -> s.substring(2, 5));
        System.out.println(str);
    }
		//對字元串進行處理返回一個字元串
    public String strHandle(String str, Function<String,String> fun){
        return fun.apply(str);
    }

Predicate: 斷言型介面

​ boolean test(T t);

    @Test
    public void test7(){
        List<String> strings = Arrays.asList("hello", "world", "qw", "das", "s", "sadui");
        List<String> str = filterStr(strings, (s) -> s.length() > 3);
        System.out.println(str.toString());
    }
    //對字元串數組進行過濾
    public List<String> filterStr(List<String> str, Predicate<String> pre){
        ArrayList<String> list = new ArrayList<>();

        for (String s : str) {
            if(pre.test(s)){
                list.add(s);
            }
        }
        return list;
    }

方法引用: 如果lambda體中的內容方法已經實現我們可以使用方法引用。

​ lambda表達式的另一種表現形式,

主要有三種語法格式:

Lambda體中方法的返回值要與實例方法返回值類型一致

  • 對象::實例方法名

    @Test
    public void test8(){
        Consumer<String> con = (s) -> System.out.println(s);
        
        Consumer<String> con1 = System.out::println;
        
        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        
        
        Employee emp = new Employee();
        Supplier<Integer> sup = () -> emp.getAge();
		Integer age = sup.get();
        
        Supplier<Integer> sup1 = emp::getAge();
        Integer age1 = sup1.get();
        
    }

  • 類::靜態方法名
    @Test
    public void test9(){
        Comparator<Integer> com = (x,y)-> Integer.compare(x,y);
        
        Comparator<Integer> com1 = Integer::compare;
        
    }
  • 類::實例方法名

    第一個參數是實例方法的調用者,第二參數是實例方法的參數才可以使用

    @Test
    public void test10(){
        BiPredicate<String,String> pre = (x,y)-> x.equals(y);
        
        BiPredicate<String,String> pre1 = String::equals;
        
    }

構造器引用:

className::new

​ 需要調用的構造器函數列表要與函數式介面中的抽象方法的參數列表保持一致

	@Test
    public void test1(){
        
        Supplier<Employee> sup = () -> new Employee();
        
        //調用的是無參構造器
        Supplier<Employee> sup1 = Employee::new;
        
        //調用的是帶有一個參數的構造器
        Function<Integer,Employee> fun = Employee::new;
        
    }

數組引用:

Type[]::new

	@Test
    public void test1(){
        
   		Function<Integer,String[]> fun = (x)-> new String[x];
        
        Function<Integer,String[]> fun1 = String[]::new;
                  
    }