《Java 8实战》 之 Lambda

《Java 8实战》 之 Lambda


Java 8 从 2014年发布至今已经经历数年累月,其中的特性多多少少用过一些,比如Lambda、Stream流等。但是没有通过系统的学习,有些原理以及使用技巧就显得黔驴技穷;有幸通过一本《Java 8 实战》系统地学习Java 8,受益颇多;为此,整理该书核心内容;作为复习巩固使用。同时,也希望对读者能起到一个学习的共鸣。目前预计整理有两part;part1:lambda 核心内容 ;part2: Steam的常规操作。

本文为第一part。让我们一起探索 Lambda 的石榴裙。

Lambda 表达式

Lambda 长什么样子

在这里插入图片描述

借助书中的例子我们可以知道,lambda主要有三部分构成:lambda参数、箭头、lambda主体

深入理解Lambda

接下来将从一个例子出发。

初始化信息

创建苹果类
@Data
@AllArgsConstructor
public class Apple {
    /**
     * 苹果颜色
     */
    private String color;

    /**
     * 苹果重量
     */
    private Integer weight;
}

此处使用lombok的 @Data来注解setter和getter方法;使用 @AllArgsConstructor 来定义全参构造函数。

初始化一堆苹果
public class LambdaTest {
    public static void main(String[] args) {
        Apple a1 = new Apple("red", 200);
        Apple a2 = new Apple("cyan", 420);
        Apple a3 = new Apple("red", 100);
        Apple a4 = new Apple("cyan", 250);
        Apple a5 = new Apple("red", 300);

        // 初始化一堆苹果
        List<Apple> apples = List.of(a1, a2, a3, a4, a5);
    }
}

此处定义5个不同重量和有红色和青色的苹果。

问题引入

  • 挑选所有青色的苹果
  • 挑选所有大的苹果(重量大等于250的苹果)
  • 挑选所有青色且较大的苹果

在没有引入lambda相关的概念时,我们的做法如下。

挑选所有青色的苹果
// 定义过滤条件
private static List<Apple> filterAppleByColor(List<Apple> apples, String color) {
    List<Apple> resApples = new ArrayList<>();
    for (Apple apple : apples) {
      	// 根据颜色筛选苹果
        if (StringUtils.equals(color, apple.getColor())) {
            resApples.add(apple);
        }
    }
    return resApples;
}



// 获取青色苹果
List<Apple> cyanApples = filterAppleByColor(apples, "cyan");

定义 filterAppleByColor 方法来筛选不同颜色的苹果。

挑选所有大的苹果(重量大等于250的苹果)
// 定义过滤条件
private static List<Apple> filterAppleByWeight(List<Apple> apples, int weight) {
    List<Apple> resApples = new ArrayList<>();
    for (Apple apple : apples) {
        if (apple.getWeight() >= weight) {
            resApples.add(apple);
        }
    }
    return resApples;
}

// 筛选大的苹果
List<Apple> bigApples = filterAppleByWeight(apples, 250);

定义 filterAppleByWeight 方法来筛选不同重量的苹果。

挑选所有青色且较大的苹果
// 挑选所有青色且较大的苹果
List<Apple> cyanAndBigApples = filterAppleByWeight(cyanApples, 250);

将所有的青色苹果在按照重量过滤一遍。

引入思考

通过上面对集合苹果列表的过滤,可以发现一个问题,我们在按照条件过滤苹果的时候,发现除了执行条件的核心地方不一样意外,其它的一模一样。

在这里插入图片描述

通过对比我们能否得出这样一个结论:

只定义一个filter,然后根据过滤的条件进行过滤就行了?

伪代码:

public List<Apple> filter(apples, filterCodition);

如果可以那么不管过滤什么条件,我们都可以调用filter,想要的条件,通过 filterCodition 传入即可。

行为参数

通过 public List filter(apples, filterCodition) 得知,我们想要得到自己想要的结果集,那么我们只需要告诉调用方法,我的行为即可。其实这里的 filterCodition 即为行为参数。

filter 方法拿到行为后,该如何做,请继续往下看。

第一次探索 - 使用匿名内部类实现

在java8中JDK定义了一个接口 Predicate;该接口源码如下。贴出核心代码。

@FunctionalInterface
public interface Predicate<T> {
		boolean test(T t);
}

从源码中可以看出,该接口的作用是,接收一个 T 对象,返回一个boolean对象。那么我们上面 过滤条件(apple.getWeight() >= weight 或 StringUtils.equals(color, apple.getColor()))是不是也能这么理解:接收一个Apple对象,返回过滤条件是否为true。

使用 **函数式接口(Predicate 即为函数式接口,后面会讲到) **进行过滤。

private static List<Apple> filter(List<Apple> apples, Predicate<Apple> predicate) {
    List<Apple> resApples = new ArrayList<>();
    for (Apple apple : apples) {
        // 此处根据行为进行过滤
        if (predicate.test(apple)) {
            resApples.add(apple);
        }
    }
    return resApples;
}

调用filter方法。

// 第一次尝试 - 查询所有红色苹果
List<Apple> redApples1 = filter(apples, new Predicate<Apple>() {
    @Override
    public boolean test(Apple apple) {
        return "red".equals(apple.getColor());
    }
});

// 第一次尝试 - 查询所有小苹果
List<Apple> smallApples1 = filter(apples, new Predicate<Apple>() {
    @Override
    public boolean test(Apple apple) {
        return apple.getWeight() < 250;
    }
});

为了凸显重要性截图标注代码。

在这里插入图片描述

注意:通过filter可以看出我们已经将核心条件抽出到 predicate.test(apple) 这样就可以实现,根据传入的行为过滤。

在这里插入图片描述

可以看出通过匿名内部类中的过滤条件替换了 predicate.test(appler) 中的内容,这就是行为参数的核心所在,此处如果不明白,一定要多看几遍熟悉下来,因为这个是关键,很多接口都类似于该道理实现的,比如 Comparator.comparing(Predicate) 也是类似的实现。

通过上面的实现我们发现已经实现了我们想要的效果那就是可以通过传入行为进行过滤内容了。那么这个和我们的主角lambda又有什么关系呢?

第二次探索 - 引入lambda

上面的实现有个缺点,那就是太啰嗦,如何杜绝啰嗦呢?那就用引入主题lambda。我们可以使用lambda进行如下的改造。

// 第二次尝试 - 查询所有红色苹果
List<Apple> redApples2 = filter(apples, (Apple apple) -> {
    return "red".equals(apple.getColor());
});

// 第二次尝试 - 查询所有小苹果
List<Apple> smallApples2 = filter(apples, (Apple apple) -> {
    return apple.getWeight() < 250;
});

可以看出使用lambda后,代码简洁了好多。

以上的代码还可以从三个点进行优化。

1.lambda 可以省略参数类型,因为在编译的时候会进行自动推断。

2.当lambda只有一个参数的时候可以省略括号。

3.当lambda return 语句只有一个话的时候可以省略大括号和return。

第三次尝试 - 优化lambda表达式

// 第三次尝试 - 查询所有红色苹果
List<Apple> redApples3 = filter(apples, apple -> "red".equals(apple.getColor()));

// 第三次尝试 - 查询所有小苹果
List<Apple> smallApples3 = filter(apples, apple -> apple.getWeight() < 250);

完整代码 - 如果掌握可以跳过本小段

Apple 类

@Data
@AllArgsConstructor
public class Apple {
    /**
     * 苹果颜色
     */
    private String color;

    /**
     * 苹果重量
     */
    private Integer weight;
}

Main 类

public class LambdaTest {
    public static void main(String[] args) {
        Apple a1 = new Apple("red", 200);
        Apple a2 = new Apple("cyan", 420);
        Apple a3 = new Apple("red", 100);
        Apple a4 = new Apple("cyan", 250);
        Apple a5 = new Apple("red", 300);

        // 初始化一堆苹果
        List<Apple> apples = List.of(a1, a2, a3, a4, a5);


        // 筛选青色苹果
        List<Apple> cyanApples = filterAppleByColor(apples, "cyan");

        // 筛选大的苹果
        List<Apple> bigApples = filterAppleByWeight(apples, 250);

        // 挑选所有青色且较大的苹果
        List<Apple> cyanAndBigApples = filterAppleByWeight(cyanApples, 250);


        // 第一次尝试 - 查询所有红色苹果
        List<Apple> redApples1 = filter(apples, new Predicate<Apple>() {
            @Override
            public boolean test(Apple apple) {
                return "red".equals(apple.getColor());
            }
        });

        // 第一次尝试 - 查询所有小苹果
        List<Apple> smallApples1 = filter(apples, new Predicate<Apple>() {
            @Override
            public boolean test(Apple apple) {
                return apple.getWeight() < 250;
            }
        });

        // 第二次尝试 - 查询所有红色苹果
        List<Apple> redApples2 = filter(apples, (Apple apple) -> {
            return "red".equals(apple.getColor());
        });

        // 第二次尝试 - 查询所有小苹果
        List<Apple> smallApples2 = filter(apples, (Apple apple) -> {
            return apple.getWeight() < 250;
        });

        // 第三次尝试 - 查询所有红色苹果
        List<Apple> redApples3 = filter(apples, apple -> "red".equals(apple.getColor()));

        // 第三次尝试 - 查询所有小苹果
        List<Apple> smallApples3 = filter(apples, apple -> apple.getWeight() < 250);
    }

    private static List<Apple> filterAppleByColor(List<Apple> apples, String color) {
        List<Apple> resApples = new ArrayList<>();
        for (Apple apple : apples) {
            if (StringUtils.equals(color, apple.getColor())) {
                resApples.add(apple);
            }
        }
        return resApples;
    }

    private static List<Apple> filterAppleByWeight(List<Apple> apples, int weight) {
        List<Apple> resApples = new ArrayList<>();
        for (Apple apple : apples) {
            if (apple.getWeight() >= weight) {
                resApples.add(apple);
            }
        }
        return resApples;
    }


    private static List<Apple> filter(List<Apple> apples, Predicate<Apple> predicate) {
        List<Apple> resApples = new ArrayList<>();
        for (Apple apple : apples) {
            // 此处根据行为进行过滤
            if (predicate.test(apple)) {
                resApples.add(apple);
            }
        }
        return resApples;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值