简化开发,巧用Lambda表达式与stream流

目录

1. lambda表达式作用

lambd表达式快速入门

2. lambda表达式

2.1 lambda表达式省略规则

 2.2 使用idea快捷键

3.  stream流

3.1 stream示例

3.2 stream流的获取方式

单列集合

数组

双列集合

3.3 常见中间操作

 3.4 常见终结操作

查找与匹配

reduce归并

4. stream流下巧用idea

5. stream流技巧


1. lambda表达式作用

lambda表达式本质是语法糖,由编译器将代码转换为常规代码,是Java8的新特性,主要优点如下:

  • 代码简洁,开发快速
  • 接近自然语言,易于理解
  • 易于“并发编程” (eg:对大数据处理时,并行流,可以多线程操作

并行流可查看文章:函数式接口、方法引用“::”简化、并行流 && idea源码英文翻译-CSDN博客

lambd表达式快速入门

以Java中自带的list.forEach()为例,该接口的入参是Consumer类型,并重写accept实现功能,代码如下所示:

    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b", "c");
        list.forEach(new Consumer<String>() {
            public void accept(String s) {
                System.out.println(s);
            }
        });
    }

此时,lambda表达式可以将代码简化为一行,易于阅读和简洁。

//Lanmbda表达式
list.forEach(s -> System.out.println(s));

2. lambda表达式

2.1 lambda表达式省略规则

代码实现对arr数组遍历输出,以该代码为例

import java.util.function.IntConsumer;

public class Main {
    public static void main(String[] args) {
        //最开始展示格式
        foreachArr(new IntConsumer() {
            @Override
            public void accept(int value) {
                System.out.println(value);
            }
        });
        //切换为待简化lambda格式
        foreachArr((int value) -> {
            System.out.println(value);
        });
    }
    /**
     * @param consumer : IntConsumer是java8提供的函数式接口之一,意思为消费者,
     *                 接受参数而不返回值,Consumer期望通过方法的实现来执行具体的操作。
     * accept为IntConsumer下的可实现方法,接受一个参数且没有返回值。
     */
    public static void foreachArr(IntConsumer consumer){
        int[] arr = {1, 2, 3, 4, 5, 6};
        for(int i : arr){
            consumer.accept(i);
        }
    }
}
  • 参数类型可以省略

如果参数列表可以被编译器自行推倒,可以删除参数类型

foreachArr((value) -> {System.out.println(value);});
  • 方法体只有一句代码时大括号和唯一一句代码的分号可以省略
foreachArr((value) -> System.out.println(value));
  • 方法只有一个参数时小括号可以省略不记
foreachArr(value -> System.out.println(value));

以上规则只供学习,如果记不住,可查看“2.2 使用idea快捷键”,转化的即为最简格式

 2.2 使用idea快捷键

在idea中,通过alt + enter可以快捷键,自动优化得到lambda表达式,如下所示:

3.  stream流

3.1 stream示例

以下代码中,通过stream流进行了去重和过滤,最终输出“1,2,3”。其中,forEach属于终结操作,流要动起来,必须依赖终结操作

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 2, 3, 4, 5, 6));
        list.stream() //把集合转换为流
                .distinct() //去重
                .filter(arr -> arr < 4) //过滤
                .forEach(arr -> System.out.println(arr)); //遍历输出

    }
}

3.2 stream流的获取方式

在使用流功能前,必须得到stream流,下面介绍stream流的几种创建方式。

单列集合

集合对象.stream

List<Student> students = getStudents();
Stream<Student> stream = students.stream();

数组

Arrays.stream(数组)  || Stream.of()来创建

Integer[] arr = new Integer[]{1, 2, 3};
Stream<Integer> stream = Arrays.stream(arr); //Arrays.stream创建
Stream<Integer> arr1 = Stream.of(arr); //Stream.of()创建

双列集合

转换为单列集合后在创建

Map<String, Integer> map = new HashMap<>();
map.put("乐乐", 18);
map.put("兴兴", 16);
map.put("乐乐", 20);
// 通过键获取stream流
Stream<String> stream = map.keySet().stream();
// 通过键值对获取stream流
Stream<Map.Entry<String, Integer>> stream1 = map.entrySet().stream();

3.3 常见中间操作

  • fifter:符合条件,则保留在流当中
  • map:对流中的元素进行计算 || 转换(eg: 对流中每个元素,拼接"map"字符)
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 2, 3, 4, 5, 6));
list.stream() //把集合转换为流
        .map(arr -> arr + "map") //拼接字符"map"
        .forEach(str -> System.out.println(str)); //遍历输出
  • distinct:去重,底层依赖Object的equals方法比较,自定义Student类要注意重写equals方法
  • sorted:排序,自定义Student类要注意重写compareTo方法 || sorted中实现new Comparator中的compare方法
  • limit:设置流的最大长度,超出部分被抛弃(eg:limit(2),存在10个元素,后续8个被抛弃)
  • skip:跳过流中的前n个元素,返回剩下元素
  • flatMap:一个对象转换为多个流对象

    eg:存在Author对象,Author存在属性List<Book> books。authors中包含3个作家,每个作家的List<Book>中包含二本书。

在flatMap中,以下代码把所有authos的List<Book>,全部转换为Book流对象,此时流存在6个Book对象。flatMap中要求返回的是Steam对象

// 此时流中6个Book对象
authors.stream()
        .flatMap(author -> author.getBooks().stream());

在map中,则只能得到3个List<Book>,map要求返回的是Object对象。

// 此时流中3个对象,每个对象结构是List<Book>
authors.stream()
        .map(author -> author.getBooks());

 3.4 常见终结操作

  • forEach:对元素进行遍历,并可进行操作
  • count:获取当前流中的元素个数。count()方法不需要入参,但注意接收返回值
long count = list.stream() //把集合转换为流
        .distinct()
        .count();//得到元素个数
  • max & min:获取流中最值,返回的是Optional对象
Optional<Integer> max = list.stream() //把集合转换为流
        .max((o1, o2) -> o1 - o2);// 设置比较规则
  • collect:把当前流转换为一个集合。eg:获取一个存放所有作者名字的list集合。
list.stream()  //转换为stream流
        .map(author -> author.getName())  //map计算得到name属性
        .collect(Collectors.toList());  //转换为list集合,Collectors.toList()能够返回collect()所需要的参数类型

转换为set集合:collect(Collectors.toSet())

转换为map集合:collect(Collectors.toMap(author -> author.getName, author -> author.getBooks())

查找与匹配

  •  anyMatch:是否存在符合匹配条件的元素,结果为boolean类型
  • allMatch:所有元素都匹配判断条件,则返回true,否则false
  • noneMAtch:都不符合判断条件,则返回true,否则false
  • findAny:获取流中的任意一个元素,存在随机性。eg:获取任意一个年龄大于18的作家。
  • findFirst:获取流中的第一个元素

reduce归并

对流中的数据按照计算方式计算出一个结果(流中所有元素聚合为一个)

list.stream()  //转换为stream流
        .map(author -> author.getAge())  //map计算得到name属性
        .reduce(0, (res, element) -> res + element);  //identity定义res初始值为0,参数二定义累加

如果对reduce中的参数不清楚,可以查看idea提示符,看传参是哪种类型。通过原有new方法,然后再alt + enter简化为lambda表达式。

 reduce也可以传一个参数,如上图第二行,即为一个参数,源码中此时默认初始化值为null,后续初始值被赋值为流中第一个元素

4. stream流下巧用idea

在idea下打断点,点击2,在3中即可得到stream流的详细情况。

以上是lanbda表达式和stream流的相关介绍,详细学习可参考B站视频:lambda与stream流编程的学习

5. stream流技巧

  1. 没有终结操作,中间操作不会执行
  2. 流是一次性的,同一个stream对象不能二次使用,需再次list.stream()新建stream对象
  3. 流不会影响原来集合中的元素(如流中,直接student.setAge,会导致属性改变,原因可查看:Java中只存在值传递,调用函数赋值未修改异常-CSDN博客
  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值