java8-lambda(1)

文章目录

  • 1. 前言
  • 2. 示例
    • 2.1.1 `lambda`替代匿名类1
    • 2.1.2 `lambda`替代匿名类2
    • 2.1.3 `lambda`替代匿名类的综合示例

1. 前言

Java 8 新特性简介

  • 速度更快
    • 修改底层数据结构:如HashMap(数组-链表-红黑树),HashSet,ConcurrentHashMap(CAS算法)
    • 修改垃圾回收机制:取消堆中的永久区(PremGen)->回收条件苛刻,使用元空间(MetaSpace)->直接使用物理内存->加载类文件
  • 代码更少(增加了新的语法Lambda表达式)
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常 Optional容器类

lambda最主要的使用场景:

  1. 替代匿名类,如runnablecomparetor等;
  2. 遍历集合;
  3. map(),reduce()等;
  4. filter()

lambda的语法:

  1. (params) -> expression;
  2. (params) -> statement;
  3. (params) -> {statements}
    如果你的方法并不改变任何方法参数,比如只是输出,那么可以简写如下:
    () -> System.out.println("Hello Lambda Expressions");
    如果你的方法接受两个方法参数,如下:
    (int even, int odd) -> even + odd

2. 示例

2.1.1 lambda替代匿名类1

实现比较器:
before java8:

     Comparator<Integer> comparator = new Comparator<Integer>() {
         @Override
         public int compare(Integer o1, Integer o2) {
             return o2-o1;//降序
         }
     };
     TreeSet treeSet = new TreeSet(comparator);

或者直接将比较器写在需要比较器的位置:

	  List list = new ArrayList();
      list.add(1);
      list.add(2);
      Collections.sort(list, new Comparator<Integer>() {
          @Override
          public int compare(Integer o1, Integer o2) {
              return o2 - o1;//降序
          }
      });
      System.out.println(list);//[2,1]

java8:
在需要匿名类的地方,即通过new接口再实现的地方,都可以使用lambda
实现比较器只需要:

	Comparator<Integer> comparator1 = (x,y)->y-x;//降序

or:

    Comparator<Integer> comparator2 = (x,y)->Integer.compare(y,x);//降序

    TreeSet<Integer> treeSet = new TreeSet<>(comparator1);
    treeSet.add(1);
    treeSet.add(2);
    System.out.println(treeSet);//[2,1]

2.1.2 lambda替代匿名类2

实现线程
before java8:

    @Test
    public void threadTest(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("new thread..."+Thread.currentThread().getName());
                //Thread-0
            }
        }).start();
        System.out.println(Thread.currentThread().getName());//main
    }

以上代码有两个线程,Thread-0main(都为默认名)。 Thread方法需要一个线程实例,传统方法仍然是new接口的实现来实现。

java8:
替代匿名类,需要关注的是:
是对接口中待实现方法的实现,因此要对应到原方法中的参数

   new Thread(()-> System.out.println(Thread.currentThread().getName())).start();
    //Thread-1

上述run方法中无参数,因此lambda中只需()即可


2.1.3 lambda替代匿名类的综合示例

对以下员工信息进行年龄和薪水过滤

@Setter @Getter @AllArgsConstructor @ToString
public class Employee {
    private int age;
    private int salary;
}

通常有的方法有:

① 普通过滤方法(缺点:扩展性差)

 public List<Employee> filterEmplyeesByAge(List<Employee> list){...}
 public List<Employee> filterEmplyeesBySalary(List<Employee> list){...}
 public List<Employee> filterEmplyeesByOther(List<Employee> list){...}

当需要增加过滤条件时,就需要写很多的过滤方法。为了改进,我们可以只写一个过滤方法,传入过滤添加即可。如下。

优化1:

②策略设计模式

我们需要写一个过滤接口,再写实现类。用于识别不用的过滤方法。

(A) 过滤接口:

public interface MyPredicate<T> {
    boolean filter(T t);
}

其中,T表示要过滤的类型,如果该接口不再用于其他类的过滤,其实这里可以写死Employee

(B) 接口的实现类

public class EmployeeSalaryFilter implements MyPredicate<Employee> {
    @Override
    public boolean filter(Employee emp) {
        return emp.getSalary()>2000;
    }
}

这里是一个过滤工资的类。是通过实例作为参数传入到过滤方法的。通用过滤方法如下:

(C ) 通用过滤方法

    public static List<Employee> filterEmployee(List<Employee> emps,MyPredicate<Employee> myPredicate){
        List<Employee> res = new ArrayList<>();
        for (Employee emp : emps) {
            if(myPredicate.filter(emp)){
                res.add(emp);
            }
        }
        return res;
    }

测试:

	@Test
    public void employeeTest(){
        Employee e1=new Employee(20,1800);
        Employee e2=new Employee(30,2800);
        Employee e3=new Employee(40,3800);
        List<Employee> employees = new ArrayList<>();
        employees.add(e1);
        employees.add(e2);
        employees.add(e3);
        //1.策略方法过滤
        List<Employee> emps = Employee.filterEmployee(employees,new EmployeeSalaryFilter());
        System.out.println(emps);
        //[Employee(age=30, salary=2800), Employee(age=40, salary=3800)]

    }

分析:上述策略模式
优点是:

  • 过滤方法只写了一个,过滤的方法,实际上调用的是过滤类中的过滤方法;

缺点是:

  • 增加不同的过滤时,需要写不同的实现类来实现,繁琐。

优化2:

对于每次新增过滤条件时,都要写实现类,来实现接口,比较繁琐,可能要实现很多个接口:

public class EmployeeSalaryFilter implements MyPredicate<Employee> {...}
public class EmployeeAgeFilter implements MyPredicate<Employee> {...}
public class EmployeeOtherFilter implements MyPredicate<Employee> {...}
...

单独创建类是非常多余的,因此优化方式是:匿名内部类。

	@Test
    public void employeeTest(){
        Employee e1=new Employee(20,1800);
        Employee e2=new Employee(30,2800);
        Employee e3=new Employee(40,3800);
        List<Employee> employees = new ArrayList<>();
        employees.add(e1);
        employees.add(e2);
        employees.add(e3);
        //1.策略方法过滤
        List<Employee> emps = Employee.filterEmployee(employees,new EmployeeSalaryFilter());
        System.out.println(emps);//[Employee(age=30, salary=2800), Employee(age=40, salary=3800)]
        
        //2.上述方式使用匿名内部类改进
        List<Employee> emps2 = Employee.filterEmployee(employees, new MyPredicate<Employee>() {
            @Override
            public boolean filter(Employee employee) {
                return employee.getSalary()>2000;
            }
        });
        System.out.println(emps2);
        //[Employee(age=30, salary=2800), Employee(age=40, salary=3800)]

    }

分析:上述匿名内部类,不需要额外再写实现类,再需要使用的时候,直接用内部类实现。

优化3:
lambda

   //3.lambda
    List<Employee> emps3 = Employee.filterEmployee(employees,(e)->e.getSalary()>2000);
    emps3.forEach(System.out::println);

优化4:
stream api

   //4.stream() api
   List<Employee> emps4 = employees
           .stream()
           .filter(e->e.getSalary()>2000)
           .collect(Collectors.toList());
   System.out.println(emps4);
   //[Employee(age=30, salary=2800), Employee(age=40, salary=3800)]
   System.out.println("------------------");

   employees.stream()
            .map(Employee::getAge)
            .forEach(System.out::println);

你可能感兴趣的:(#,java新特性)