JDK8--02:为什么要使用lambda

Posted liconglong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK8--02:为什么要使用lambda相关的知识,希望对你有一定的参考价值。

lambda是一个匿名函数,我们可以把lambda理解为一个可以传递的代码(将代码像数据一样传递),可以写出更简洁更灵活的代码。
首先看一下原来的匿名内部类实现方式(以比较器为例)
    //原来的匿名内部类实现方式
    public void test1(){
        //定义一个匿名内部类comparator
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        //将匿名内部类作为对象传入
        TreeSet<Integer> treeSet = new TreeSet<>(comparator);
    }

 以上代码实际上实际有用的代码只有两行(第7行),但是却需要写这么多代码,非常痛苦,lambda就很好的解决了该问题。

 lambda实现方式

    //lambda表达式实现
    public void test2(){
        //lambda表达式
        Comparator<Integer> comparator = (x,y)->Integer.compare(x,y);
        //将匿名内部类作为对象传入
        TreeSet<Integer> treeSet = new TreeSet<>(comparator);
    }

 通过以上可以看到,原来的多行代码,变为了一行实现,代码量大大减少,但是,如果只是这样的一个结论,显然不能说服人(匿名内部类我直接就可以一键生成,对开发来说影响并不是很大,反而要学习一个新的语法,这种投入产出比不太大)
 所以再举一个例子来说明lambda的优势:

 需求1:获取公司中年龄大于35岁的员工

  先创建实体类

package com.example.jdk8demo.lambda;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

@Data
@RequiredArgsConstructor
@AllArgsConstructor
@ToString
public class Employer {
    private String name;
    private Integer age;
    private double salary;
}

  为了方便演示,就不再进行数据库操作,直接模拟一个员工集合

/**
     * 模拟员工集合
     */
    private List<Employer> list = Arrays.asList(
            new Employer("张三",18,2222.22),
            new Employer("李四",32,3333.33),
            new Employer("王五",52,4444.44),
            new Employer("赵六",44,5555.55),
            new Employer("田七",8,4235.32),
            new Employer("牛八",28,3256.52)
    );

  然后就是实现逻辑代码,我们一般会直接定义一个方法去实现,如下代码所示

/**
     * 查询年龄大于35岁的员工
     * @return
     */
    public List<Employer> getEmpolyerByAge(){
        List<Employer> employerList = new ArrayList<>();
        for (Employer employer : list){
            if(employer.getAge() > 35){
                employerList.add(employer);
            }
        }
        return employerList;
    }

  那么如果此时,又来了一个需求

 需求2:查询工资大于4000的员工

  我们还需要再写一个实现方法

/**
     * 查询工资大于4000的员工
     * @return
     */
    public List<Employer> getEmpolyerBySalary(){
        List<Employer> employerList = new ArrayList<>();
        for (Employer employer : list){
            if(employer.getSalary() > 4000){
                employerList.add(employer);
            }
        }
        return employerList;
    }

  可以发现,两个方法中,只有  employer.getAge() > 35 和 employer.getSalary() > 4000 是不同的,其余的代码都一样,如果后续还有新的类似需求增加,呢么冗余代码会越来越多,因此我们就需要对代码进行优化。

优化方案一:使用策略模式

  一般情况下,对于这种冗余代码,我们的优化会使用策略模式进行优化

  首先,先创建一个接口

package com.example.jdk8demo.lambda;

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

  然后针对不同的需求,做不同的实现类

  第一个实现类是针对查询年龄大于35的员工

package com.example.jdk8demo.lambda;

public class EmpolyerImplByage implements EmpolyerService<Employer> {
    @Override
    public boolean filter(Employer employer) {
        return employer.getAge() > 35;
    }
}

  第二个实现类是针对查询公司大于4000的员工

package com.example.jdk8demo.lambda;

public class EmpolyerImplBySalary implements EmpolyerService<Employer> {
    @Override
    public boolean filter(Employer employer) {
        return employer.getSalary() > 4000;
    }
}

  然后就是使用策略模式进行查询,方法的入参是接口的实现类,然后根据实现类中对接口方法的不同实现进行不同的处理。

/**
     * 使用策略模式查询员工信息
     * @param empolyerService
     * @return
     */
    public List<Employer> getEmpolyerList(EmpolyerService<Employer> empolyerService){
        List<Employer> employerList = new ArrayList<>();
        for (Employer employer : list){
            if(empolyerService.filter(employer)){
                employerList.add(employer);
            }
        }
        return employerList;
    }

  最后所有需求都统一调用新增的策略模式方法,具体的入参就是接口具体的实现类

/**
     * 优化一:采用策略模式
     */
    public void test5(){
        List<Employer> employerList = getEmpolyerList(new EmpolyerImplByage());
        for (Employer employer : employerList){
            log.info(employer.toString());
        }
        log.info("=============================================");
        employerList = getEmpolyerList(new EmpolyerImplBySalary());
        for (Employer employer : employerList){
            log.info(employer.toString());
        }
    }

  这种优化也有不好的地方,就是一个需求就要创建一个实现类,随着需求的增加,实现类会越来越多,所以可以进一步进行优化

优化方案二:使用匿名内部类

  由于采用策略模式,一个需求就需要创建一个实现类,导致文件增多,因此可以将策略模式改为使用匿名内部类,使用匿名内部类,仍然需要上述的过滤接口,但是无需再使用接口的实现类

/**
     * 优化方式二:匿名内部类
     */
    public void test6(){
        List<Employer> employerList = getEmpolyerList(new EmpolyerService<Employer>() {
            @Override
            public boolean filter(Employer employer) {
                return employer.getAge() > 20;
            }
        });
        for (Employer employer : employerList){
            log.info(employer.toString());
        }
        log.info("=============================================");
        employerList = getEmpolyerList(new EmpolyerService<Employer>() {
            @Override
            public boolean filter(Employer employer) {
                return employer.getSalary() > 3000;
            }
        });
        for (Employer employer : employerList){
            log.info(employer.toString());
        }
    }

  由此已经对应了本文刚开始的时候,匿名内部类中有用的代码实际就一行,但是缺需要写大量其他无用的代码,因此可以使用lambda进行优化。

优化方案三:使用lambda

/**
     * 优化方式七:lambda表达式
     */
    public void test7(){
        LambdaTest lambdaTest = new LambdaTest();
        List<Employer> employerList = lambdaTest.getEmpolyerList((e) -> e.getAge()>30);
        employerList.forEach(System.out::println);
        log.info("=============================================");
        employerList = lambdaTest.getEmpolyerList((e)->e.getSalary()>3000);
        employerList.forEach(System.out::println);
    }

  可以发现,使用lambda表达式后,代码简单、简洁。到此处,为什么要使用lambda已经描述完毕,但是对于java8来说,还有更简洁的优化方式,就是Stream流。

优化方式四:Stream流

  此种实现,不需要像前三种优化方式一样新建接口,这里直接使用流式过滤即可。

/**
     * 使用StreamAPI查询员工信息
     */
    public void test8(){
        list.stream()//流式处理
                .filter((e)->e.getSalary()>2000)//过滤出工资大于2000的员工
                .filter((e)->e.getAge()>30)//过滤出年龄大于30的员工
                .limit(2)//只查询前两条
                .forEach(System.out::println);//循环打印
    }

 

以上是关于JDK8--02:为什么要使用lambda的主要内容,如果未能解决你的问题,请参考以下文章

重学Java 8新特性 | 第3讲——我们为什么要使用Lambda表达式?

重学Java 8新特性 | 第3讲——我们为什么要使用Lambda表达式?

重学Java 8新特性 | 第3讲——我们为什么要使用Lambda表达式?

Python匿名函数lambda是什么?为什么要匿名?怎么用?

为啥要使用lambda表达式?原来如此,涨知识了

Java8新特性你知道Java8为什么要引入Lambda表达式吗?