1、

Comparator接口:

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);

(1)匿名内部类

   @Test
    public void test1() {
        Comparator<Integer> com = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
    }

(2)Lambda表达式

  @Test
    public void test2(){
        Comparator<Integer> com=(o1,o2)->Integer.compare(o1,o2);
    }

(3)案例(获取年龄大于35的员工信息)

常规方式:

定义一个员工类,遍历所有员工的信息,将年龄大于35的员工的信息存储到新的集合中。但是,如果把需求改为获取工资大于5000的员工信息,只需要改变的是程序的判断条件,这就造成了代码的冗余

设计模式:策略设计模式

新建一个员工类

@Data
@AllArgsConstructor
public class Employee {
    private int id;
    private String name;
    private int age;
    private double salary;
}

创建一个接口,该接口定义一个用于过滤的方法

@FunctionalInterface
public interface MyPredicate<T> {

    public boolean test(T t);
    
}

创建两个接口的实现类:实现类重写接口的方法分别过滤年龄和工资

工资

public class FilterEmployeeForSalary implements MyPredicate<Employee> {

    @Override
    public boolean test(Employee t) {
        return t.getSalary() >= 5000;
    }

}

年龄

public class FilterEmployeeForAge implements MyPredicate<Employee>{

    @Override
    public boolean test(Employee t) {
        return t.getAge() <= 35;
    }

}

测试类:

添加员工的信息

定义过滤方法,该方法的第一个参数是一个Employee类型的List集合,第二个参数是一个接口类型的,也就是说可以传递该接口的所有实现类,也就是说没有将方法写死,方法的灵活度更高了

第三个方法是测试类,传递员工的信息和接口的实现类,返回的是过滤后的结果

public class TestLambda {
    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 18, 9999.99),
            new Employee(102, "李四", 59, 6666.66),
            new Employee(103, "王五", 28, 3333.33),
            new Employee(104, "赵六", 8, 7777.77),
            new Employee(105, "田七", 38, 5555.55)
    );

    public List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> myPredicate) {
        List<Employee> employees = new ArrayList<>();
        for (Employee employee : list) {
            if (myPredicate.test(employee)) {
                employees.add(employee);
            }
        }
        return employees;
    }

    @Test
    public void test() {
        List<Employee> employeeList = filterEmployee(emps, new FilterEmployeeForAge());
        for (Employee employee : employeeList) {
            System.out.println(employee);
        }
        System.out.println("-------------------");
        List<Employee> list = filterEmployee(emps, new FilterEmployeeForSalary());
        for (Employee employee : list) {
            System.out.println(employee);
        }
    }

测试结果:

Employee(id=101, name=张三, age=18, salary=9999.99)
Employee(id=103, name=王五, age=28, salary=3333.33)
Employee(id=104, name=赵六, age=8, salary=7777.77)
-------------------
Employee(id=101, name=张三, age=18, salary=9999.99)
Employee(id=102, name=李四, age=59, salary=6666.66)
Employee(id=104, name=赵六, age=8, salary=7777.77)
Employee(id=105, name=田七, age=38, salary=5555.55)

匿名内部类方式

public List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> myPredicate) {
        List<Employee> employees = new ArrayList<>();
        for (Employee employee : list) {
            if (myPredicate.test(employee)) {
                employees.add(employee);
            }
        }
        return employees;
    }

    @Test
    public void test() {
        List<Employee> list = filterEmployee(emps, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getSalary() < 7000;
            }
        });
        for (Employee employee : list) {
            System.out.println(employee);
        }
    }

匿名内部类方式与策略模式相比,少了对实现类的书写,但是匿名内部类的方式还是不够简洁

Lambda表达式

    public List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> myPredicate) {
        List<Employee> employees = new ArrayList<>();
        for (Employee employee : list) {
            if (myPredicate.test(employee)) {
                employees.add(employee);
            }
        }
        return employees;
    }

    @Test
    public void test() {
        List<Employee> list = filterEmployee(emps,(e)->e.getSalary()<7000);
        for (Employee employee : list) {
            System.out.println(employee);
        }
    }

与函数时接口的方式相比,Lambda表达式的方式使得代码更加简洁

最简洁的方式:Stream API

  @Test
    public void test() {
        emps.stream()
                .filter((e)->e.getSalary()>=5000)
                .forEach(System.out::println);
    }

此种方式只需要一个实体类

 

2、函数式接口

(1)定义一个函数式接口

@FunctionalInterface
public interface MyFun {

    public Integer getValue(Integer num);
    
}

(2)定义方法并测试

public class TestLambda {
    public Integer operation(Integer num, MyFun mf) {
        return mf.getValue(num);
    }

    @Test
    public void test() {
        Integer num = operation(100, (x) -> x * x);
        System.out.println(num);

        System.out.println(operation(200, (y) -> y + 200));
    }
}

方法一的参数是一个接口类型的,该方法调用了接口内的方法

方法二是测试方法,Lambda表达式需要传递一个参数

 

3、Lambda表达式的应用

(1)排序

函数式接口

int compare(T o1, T o2);

调用函数式接口的方法

   public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

测试类

    List<Employee> emps = Arrays.asList(
            new Employee(101, "张三", 18, 9999.99),
            new Employee(102, "李四", 59, 6666.66),
            new Employee(103, "王五", 28, 3333.33),
            new Employee(104, "赵六", 8, 7777.77),
            new Employee(105, "田七", 38, 5555.55)
    );

    @Test
    public void test1() {
        Collections.sort(emps, (e1, e2) -> {
            if (e1.getAge() == e2.getAge()) {
                return e1.getName().compareTo(e2.getName());
            } else {
                return Integer.compare(e1.getAge(), e2.getAge());
            }
        });

        for (Employee emp : emps) {
            System.out.println(emp);
        }
    }

(2)处理字符串

定义一个函数式接口

@FunctionalInterface
public interface MyFunction {
    
    public String getValue(String str);

}

定义字符串处理方法和测试方法

public class TestLambda {
    public String strHandler(String str, MyFunction mf){
        return mf.getValue(str);
    }
    @Test
    public void test2(){
        String trimStr = strHandler("   你好   ", (str) -> str.trim());
        System.out.println(trimStr);

        String upper = strHandler("qqqqeeeabc", (str) -> str.toUpperCase());
        System.out.println(upper);

        String newStr = strHandler("1234556", (str) -> str.substring(2, 5));
        System.out.println(newStr);
    }
}

(3)数据处理

函数值接口

public interface MyFunction2<T, R> {

    public R getValue(T t1, T t2);

}

测试类

public class TestLambda {
    public void op(Long l1, Long l2, MyFunction2<Long, Long> mf){
        System.out.println(mf.getValue(l1, l2));
    }
    @Test
    public void test3(){
        op(100L, 200L, (x, y) -> x + y);

        op(100L, 200L, (x, y) -> x * y);
    }
}

 

 

总结

  匿名内部类能够避免接口的实现类的书写,但是还可以通过Lambda表达式进一步简化,Lambda表达式的应用需要借助于函数式接口,JDK中自带的有一些函数式接口,可以拿来直接使用

  Lambda表达式的箭头左边用来书写输入参数,右边是函数式接口方法的实现

 

每个人都会有一段异常艰难的时光 。 生活的压力 , 工作的失意 , 学业的压力。 爱的惶惶不可终日。 挺过来的 ,人生就会豁然开朗。 挺不过来的 ,时间也会教你 ,怎么与它们握手言和 ,所以不必害怕的。 ——杨绛