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

lambda是一个匿名函数,我们可以把lambda理解为一个可以传递的代码(将代码像数据一样传递),可以写出更简洁更灵活的代码。
首先看一下原来的匿名内部类实现方式(以比较器为例)
1
2
3
4
5
6
7
8
9
10
11
12
//原来的匿名内部类实现方式
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实现方式

1
2
3
4
5
6
7
//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);//循环打印
    }
复制代码

 

posted @   李聪龙  阅读(291)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示