Java 8之stream进阶

前言:

上一篇文章 Java 8之stream介绍和使用 中讲解了stream的定义和用法,简单介绍几个最基本最常用的方法,其实stream还有更强大的功能,这篇文章就会给大家介绍stream的进阶用法。


筛选:

在上一篇文章中我们介绍了使用filter方法来筛选元素,filter方法接受一个Predicate类型的参数,我们可以传入一个Lamada表达式或者方法引用,原理在 Java 8之方法引用和Lambda表达式 中已经将结果。我们实际上是传入了一个条件,然后筛选出符合条件的元素,例如下面的这行代码就是筛选出年龄大于20的人。

List<Person> list = peoples.stream().filter(person -> person.getAge()>20).collect(toList());

实际上stream还有别的方法可以进行筛选,下面我们来介绍几个常用的。

  • distinct,这个方法可以帮助我们去重

    List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
    numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);
  • limit,这个方法可以让我们只取stream中的前几个,值得注意的是当我们用Set集合来存储元素时,因为Set是无序的,所以每次我们取到的前几个元素也会是无序的。

    List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
    numbers.stream().limit(3).forEach(System.out::println);
  • skip,这个方法可以让我们跳过元素,跳过多少个元素由我们指定。

    List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
    numbers.stream().skip(3).forEach(System.out::println);

映射:

我们经常遇到从对象中抽取自己需要的元素放入一个新的类型的集合中的情况,这就是映射操作,而stream在这方面也提供了非常强大的支持。

  • map,这个方法接受一个Lambda表达式,它会遍历整个流把这个函数作用到每个元素上,然后把输出的结果放到一个新流中。

    // 获取每个元素的name属性放入一个新流中,然后把这个流转为List类型。
    List<Person> names = peoples.stream().map(Person::getName).collect(toList());
    // 获取每个元素的字符串长度放入新流中,然后转为List类型。
    List<String> words = Arrays.asList("AA", "B", "CCC", "DDDDDD");
    List<Integer> wordLengths = words.stream().map(String::length).collect(toList());
  • flatmap,这个方法比较特殊,它的作用是把多个相同类型的流连成一个流,我们看下面的代码,目的是为了把集合中的字符串都拆成单个字符然后放到一个集合,但是如果直接用map方法的话返回的ListString[]类型的,这是因为word.split("")返回的结果就是这个类型的。

    List<String> words = Arrays.asList("Hello", "world");
    List<String[]> list = words.stream().map(word -> word.split("")).collect(toList());

    在这里要提到Arrays.stream()这个方法,它的作用是接受一个数组,然后把这个数组里的元素转为一个流,所以我们可以尝试使用这个方法来改进下上面的代码。但是我们发现还是有问题,返回集合类型是Stream<String>,因为map(Arrays::stream)把数组里的每个元素都弄成了一个流。

    List<String> words = Arrays.asList("Hello", "world");
    List<Stream<String>> list = words.stream().map(word -> word.split(""))
        .map(Arrays::stream).collect(toList());

    现在flatmap的作用就出来了,我们把代码改进下,改成使用flatmap接受Arrays::stream,它的作用正是在上面map(Arrays::stream)的基础上把集合里的流里面的元素合并成一个流,所以返回的List类型就是String类型的。

    List<String> words = Arrays.asList("Hello", "world");
    List<String> list = words.stream().map(word -> word.split(""))
        .flatmap(Arrays::stream).collect(toList());

匹配:

stream同样也提供了很多方法来检查集合中是否包含了某个指定的值。注意,这些方法都属于 终端操作 ,也就是说调用了这些方法就会关闭流。

  • allMatch

    List<String> numbers = Arrays.asList("Hello", "World");
    boolean flag = numbers.stream().allMatch(string -> string.contains("z"));
    System.out.println(flag);
  • anyMatch,这个方法会检查流中是否至少有一个元素匹配给定的值,返回一个boolean值。

    List<String> numbers = Arrays.asList("Hello", "World");
    boolean flag = numbers.stream().anyMatch(string -> string.contains("z"));
    System.out.println(flag);
  • noneMatch,这个方法则是和allMatch方法做相反的操作。

    List<String> numbers = Arrays.asList("Hello", "World");
    boolean flag = numbers.stream().noneMatch(string -> string.contains("z"));
    System.out.println(flag);

查找:

对于集合的操作最重要的就是从中查找符合条件的数据了,我们来看下面的方法。

  • findAny,这个方法需要配合filter方法使用,返回把筛选出来的第一个元素。注意,这里返回的是Optional类型的对象,这个对象是Java 8新增的专门为了防止返回数据的时候遇到null的情况,后续再作详细了解,目前只需要知道它有个isPresent方法来判断元素是否为空,get方法用来取值。

    List<String> numbers = Arrays.asList("Hello", "World");
    Optional<String> optional= numbers.stream().filter(string -> string.contains("l")).findAny();
    if(optional.isPresent()){
        System.out.println(optional.get());
    }
  • findFirst,这个方法是用来取流中第一个元素的,目前看来好像没什么用,但是有时候我们可能会对流进行复杂的筛选,再选取筛选后的流中第一个元素。

    List<String> numbers = Arrays.asList("Hello", "World");
    Optional<String> optional= numbers.stream().findFirst();
    System.out.println(optional.toString());

归约:

归约就是把整个流归约成一个值的操作,比如求集合中最大的元素、所有元素值的和之类的操作。

  • reduce,这个方法就是用来对元素的值进行操作的,我们这里做加法运算。它接受两个参数,第一个是初始值,就是开始计算前就已经有一个数值了。第二个参数是一个Lambda表达式,用来对各个元素做计算。

    List<Integer> list = Arrays.asList(1,2,3,4,5);
    int sum = list.stream().reduce(0,(a,b) -> a - b);
    System.out.println(sum);

    在Java 8中Integer中新增了一个sum方法,它的作用和上面的Lambda表达效果一样,所以我们可以使用这个方法的方法引用来简化代码。

    List<Integer> list = Arrays.asList(1,2,3,4,5);
    int sum = list.stream().reduce(0,Integer::sum);
    System.out.println(sum);

    我们还可以用这个方法来求最大值和最小值,在Integer中还新增了minmax方法,等同于(x, y) -> x < y ? x : y(x, y) -> x > y ? x : y,这样我们就可以求出流中的最大值和最小值了。

    Optional<Integer> min = numbers.stream().reduce(Integer::min);
    Optional<Integer> min = numbers.stream().reduce(Integer::max);

以上就是stream的筛选、查找、匹配和归约操作中比较常用的方法了,下面还会介绍分组、分区等功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值