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 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 filterEmployee(List employees){

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

//测试方法
@Test
public void test1(){
    List 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 {

    public boolean test(T t);

}

2、定义过滤类实现我们定义的接口
  public class FilterEmployeeByAge implements MyPredicate{
    @Override
    public boolean test(Employee employee) {

        return employee.getAge()>20;
    }
}  

3、同样定义过滤方法
  //过滤方法
public List filterEmployee(List employees, Mypredicatre mp){

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

4、测试方法
   
    @Test
    public void test2(){
        List 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 employees = filterEmployee(this.employees, new MyPredicate() {
            @Override
            public boolean test(Employee employee) {
                return employee.getAge() > 20;
            }
        });
    
-----------------匿名内部类可以使用lambda表达式简化----------
    @Test
    public void test4(){
        List 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 con = (x)-> System.out.println(x);
        //Consumer con = x-> System.out.println(x);
        con.accept("hello world");
    }
  • 有两个参数,且有返回值 (有多条语句,必须使用{})
    @Test
    public void test3(){
        Comparator com = (x,y)->{
            System.out.println("函数式接口");
            return Integer.compare(x,y);
        };
    }
  • 有两个参数,且有返回值,语句只有一条 (return 和{} 可以省略)
    @Test
    public void test4(){
        Comparator 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 con){
        con.accept(money);
    }

Supplier : 供给型接口

? T get();

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

Function: 函数式接口

? 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 fun){
        return fun.apply(str);
    }

Predicate: 断言型接口

? boolean test(T t);

    @Test
    public void test7(){
        List strings = Arrays.asList("hello", "world", "qw", "das", "s", "sadui");
        List str = filterStr(strings, (s) -> s.length() > 3);
        System.out.println(str.toString());
    }
    //对字符串数组进行过滤
    public List filterStr(List str, Predicate pre){
        ArrayList list = new ArrayList<>();

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

方法引用: 如果lambda体中的内容方法已经实现我们可以使用方法引用。

? lambda表达式的另一种表现形式,

主要有三种语法格式:

Lambda体中方法的返回值要与实例方法返回值类型一致

  • 对象::实例方法名

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

  • 类::静态方法名
    @Test
    public void test9(){
        Comparator com = (x,y)-> Integer.compare(x,y);
        
        Comparator com1 = Integer::compare;
        
    }
  • 类::实例方法名

    第一个参数是实例方法的调用者,第二参数是实例方法的参数才可以使用

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

构造器引用:

className::new

? 需要调用的构造器函数列表要与函数式接口中的抽象方法的参数列表保持一致

	@Test
    public void test1(){
        
        Supplier sup = () -> new Employee();
        
        //调用的是无参构造器
        Supplier sup1 = Employee::new;
        
        //调用的是带有一个参数的构造器
        Function fun = Employee::new;
        
    }

数组引用:

Type[]::new

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