前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java Stream流:最新版技巧大揭秘,轻松搞定数据处理!

Java Stream流:最新版技巧大揭秘,轻松搞定数据处理!

作者头像
码农飞哥
发布2023-09-03 14:24:32
6420
发布2023-09-03 14:24:32
举报
文章被收录于专栏:好好学习

1. Stream流是什么?

JDK1.8 中增加了Stream流,Stream流是一种流式的处理数据的风格,也就是将要处理的数据当作流,在管道中进行传输,并在管道的每个节点对数据进行处理,如过滤、排序、转换等。

先来看一个Stream API的使用示例

代码语言:javascript
复制
       List<String> sourceList = Arrays.asList("1", "2", "", "12", "5");
        int sum = sourceList.stream()
                .filter(StringUtils::isNotBlank)
                .mapToInt(Integer::valueOf)
                .sum();
        System.out.println(sum);

这是个很简单的一个Stream使用例子,我们过滤掉空字符串后,转成int类型并对各个元素进行求和,这里有个三个操作:filter,mapToInt,sum。后面会详细介绍。

2. Stream流的执行机制

Stream内部通过流水线(Pipline)的方式来实现的,基本思路就是顺着流水线尽可能执行更多的操作,从而避免多次迭代。

Steam流操作有三个特性:

  1. Stream流不存储数据:而是按照特定的规则对数据进行计算,一般会输出结果。
  2. Stream流不改变源数据:通常情况下会产生一个新的集合或一个值。
  3. Stream流具有延迟执行特性:只有调用终端操作时,中间操作才会执行。

一个Stream流的使用主要包括三步:

  1. 生成stream流:这就就是将输入的数据源转成Stream流,数据源主要是CollectionArray等集合数据。
  2. 执行中间操作:对数据进行处理
  3. 执行终止操作:返回最终的结果

生成Stream流

生成Stream流的方式有三种,分别是

代码语言:javascript
复制
List<String> sourceList = Arrays.asList("1", "2", "", "12", "5");
//1.创建stream串行流对象
sourceList.stream();
//2.创建可并行执行的stream流对象
sourceList.parallelStream();
//3.通过给定的一系列元素创建一个新的Stream串行流对象
Stream.of("12", "123", "14", "15");

执行中间操作

执行中间操作只是一种标记,只有结束操作才会触发实际计算。调用中间操作会返回一个新的流。 过滤,排序类的操作都是中间操作,中间操作可以有多个,中间操作分为无状态和有状态。

无状态:指元素的处理不受前面元素的影响。下面的方法均是无状态操作

方法

说明

map()

将已有元素转换为另一个对象类型,一对一逻辑

filter()

按照条件过滤符号要求的元素

peek()

对Stream流中的每个元素进行逐个遍历处理

unodered()

返回一个无序的流,对于不关心顺序的数据处理和并行配合使用更佳。

mapToInt()

将已有元素转成Int类型

mapToLong()

将已有元素转成Long类型

mapToDouble()

将已有元素转成Double类型

flatMap()

将已有元素转换为另外对象类型,一对多逻辑

flatMapToInt()

将已有元素转成Int类型

有状态:有状态的中间操作必须等所有元素处理之后才知道最终结果。比如排序是有状态的操作,在读取所有元素之前并不能确定排序结果。下面方法是有状态操作

方法

说明

distinct()

对stream中所有元素进行去重

sorted()

结果排序

limit(n)

仅保留集合前面指定个数的元素

skip(n)

跳过集合前面指定个数的元素

concat()

将两个流合并起来为1个新的流

执行终止操作

终止操作就是指定stream流的输出结果。

方法

说明

count()

元素个数

max()

最大值

min()

最小值

findFirst()

第一个符合条件

findAny()

任意一个符合条件

anyMatch()

判断是否有符合条件元素

allMatch()

是否所有元素都符合条件

noneMatch()

是否所有元素都不符合

collect(Collectors进行指定)

将流转换成指定类型

toArray()

转换成数组

iterator()

转换成iterator()对象

foreach()

逐个遍历

3.使用示例(中间操作)

现在定义一个Apple类,此类有价格price,颜色color,重量weight,产地distinct 四个属性。

代码语言:javascript
复制
private static List<Apple> appleList = new ArrayList<>();

static {
    appleList.add(new Apple(10, "red", 12, "安徽"));
    appleList.add(new Apple(5, "red", 13, "江西"));
    appleList.add(new Apple(5, "blue", 10, "江西"));
    appleList.add(new Apple(40, "blue", 9, "河南"));
    appleList.add(new Apple(15, "blue", 11, "浙江"));
}
}
public class Apple {

    private Integer price;

    private String color;

    private Integer weight;

    private String district;

    public Apple(Integer price, String color, Integer weight, String district) {
        this.price = price;
        this.color = color;
        this.weight = weight;
        this.district = district;
    }
  省略getter和setter方法
}

使用filter方法过滤所有红色苹果

代码语言:javascript
复制
    //1.filter(过滤)筛选出所有颜色是红色的苹果
    List<Apple> red = appleList.stream().filter(apple -> apple.getColor().equals("red")).collect(Collectors.toList());

使用map方法,将所有苹果重量+10,并且输出对应的苹果的产地

代码语言:javascript
复制
    //2.map的使用,将所有苹果重量+10,并且输出对应的苹果的产地
appleList.stream()
                .map(apple -> {
                    apple.setWeight(apple.getWeight() + 10);
                    return apple;
                }).map(Apple::getDistrict)
                .collect(Collectors.toList());

sorted 排序方法

  • sorted():自然排序,流中元素需实现Comparable接口
  • sorted(Comparator com):Comparator排序器自定义排序
代码语言:javascript
复制
 //3.sorted() 排序
        //按价格升序排序 自然排序
        System.out.println("按价格升序排序 自然排序");
        appleList.stream().sorted(Comparator.comparing(Apple::getPrice))
                .peek(System.out::println).collect(Collectors.toList());

        //按价格倒序排序 reversed()
        System.out.println("按价格倒序排序 reversed()");
        appleList.stream().sorted(Comparator.comparing(Apple::getPrice).reversed())
                .peek(System.out::println).collect(Collectors.toList());

        System.out.println("先按价格再按重量升序排序 thenComparing");
        //先按价格再按重量升序排序 thenComparing
        appleList.stream().sorted(Comparator.comparing(Apple::getPrice)
                        .thenComparing(Apple::getWeight))
                .peek(System.out::println)
                .collect(Collectors.toList());
        //自定义排序,先按价格再按重量(降序)
        System.out.println("自定义排序,先按价格再按年龄(降序)");
        appleList.stream().sorted((p1, p2) -> {
            if (p1.getPrice() == p2.getPrice()) {
                return p2.getWeight() - p1.getWeight();
            } else {
                return p2.getPrice() - p1.getPrice();
            }
        }).peek(System.out::println).collect(Collectors.toList());

flatMap的使用

,将两个字符数组合并成一个新的字符数组

代码语言:javascript
复制
  List<List<Integer>> lists = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        list.add(4444);
        list.add(33333);
        list.add(444444);
        lists.add(list);
        lists.stream().flatMap(Collection::stream).forEach(System.out::println);

        List<String> strings = Arrays.asList("m,k,l,a", "1,3,4,5");
        List<String> listNew = strings.stream().flatMap(s -> {
            //将每个元素转成一个新的stream
            String[] split = s.split(",");
            Stream<String> s2 = Arrays.stream(split);
            return s2;
        }).collect(Collectors.toList());
        System.out.println(listNew);

  • 当使用map()操作时,不是返回一个值,而是返回一个集合或者一个数组的时候,这时候就可以使用flatMap解决这个问题。就是扁平化将每个元素映射成另一个Stream对象。

去重,合并,跳过,截取(concat,distinct,skip,limit)

代码语言:javascript
复制
//创建两个流
Stream<String> stream1 = Stream.of("1", "2", "", "12", "5");
Stream<String> stream2 = Stream.of("3", "4", "5", "6");
//concat:合并两个流    //distinct:去重
List<String> lists1 = Stream.concat(stream1, stream2)
        .distinct().collect(Collectors.toList());
//limit:限制从流中获取前n个数据
List<String> collect = stream1.limit(3).collect(Collectors.toList());
//skip:跳过前n个数据
List<String> collect1 = stream1.skip(2).collect(Collectors.toList());

终止操作

  • 分区:将stream按条件分为两个Map,比如水果按照价格是否高于12分出两部分。
  • 分组:将集合分为多个Map,比如水果按产地分组。有单级分组和多级分组。 //- 分区:将stream按条件分为两个Map,比如水果按照价格是否高于12分出两部分。 Map<Boolean, List<Apple>> collect = appleList.stream().collect(Collectors.partitioningBy(apple -> apple.getPrice() > 12)); //- 分组:将集合分为多个Map,比如水果按产地分组。有单级分组和多级分组。 Map<String, List<Apple>> collect1 = appleList.stream().collect(Collectors.groupingBy(apple -> apple.getDistrict()));
  • 计数:counting
  • 平均值:averagingInt、averagingLong、averagingDouble
  • 最值:maxBy、minBy
  • 求和:summingInt、summingLong、summingDouble //求平均重量 Double avg = appleList.stream().collect(Collectors.averagingDouble(Apple::getWeight)); //求和 Integer sum = appleList.stream().collect(Collectors.summingInt(Apple::getWeight)); //统计 List<Integer> orgNums = Arrays.asList(3, 2, 2, 3, 7, 3, 5); IntSummaryStatistics statistics = orgNums.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("列表中最大的数:" + statistics.getMax()); System.out.println("列表中最小的数:" + statistics.getMin()); System.out.println("所有数之和:" + statistics.getSum()); System.out.println("平均数:" + statistics.getAverage());
  • 聚合(max、min、count) //取出价格最高的苹果 appleList.stream().max(Comparator.comparing(Apple::getPrice)).get(); //取出价格最低的苹果 appleList.stream().min(Comparator.comparing(Apple::getPrice)).get(); //统计元素个数 appleList.stream().count();
  • 统计(counting、averaging) Collectors提供了一系列用于数据统计的静态方法:
  • 遍历/匹配(foreach、find、match) //foreach appleList.stream().filter(apple -> apple.getColor().equals("blue")) .forEach(System.out::println); //匹配第一个颜色是blue的苹果 appleList.stream().filter(apple -> apple.getColor().equals("blue")) .findFirst(); //匹配任意一个颜色是blue的苹果 appleList.stream().filter(apple -> apple.getColor().equals("blue")) .findAny(); //是否包含符合特定条件的元素 appleList.stream().anyMatch(apple -> apple.getColor().equals("blue"));
  • 归集collect(toList、toSet、toMap) appleList.stream().map(Apple::getDistrict).collect(Collectors.toList()); //调用toMap方法时,如果key重复可以如下处理 Map<String, Apple> collect = appleList.stream().collect(Collectors.toMap(Apple::getDistrict, a->a,(a1,a2)->a1)); //集合去重 Set<Apple> collect1 = appleList.stream().collect(Collectors.toSet());
  • 分区、分组(partitioningBy、groupingBy)
  • 拼接(joining) List<String> list = Arrays.asList("1","2","3","4"); //以空字符拼接,输出 1234 String result= list.stream().collect(Collectors.joining()); //以“-”符号拼接,输出1-2-3-4 String result1= list.stream().collect(Collectors.joining("-")); System.out.println(result1);

多个参数

joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) 方法接受一个字符串序列作为拼接符,并在拼接完成后添加传递的前缀和后缀。假如我们传递的分隔符为 “-”,前缀为 “[” , 后缀为 “]” 。那么输出结果为 [1-2-3-4]

代码语言:javascript
复制
    List<String> arrayList = Arrays.asList("1","2","3","4");
        String collect = arrayList.stream().collect(Collectors.joining(",", "[", "]"));
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农飞哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2. Stream流的执行机制
    • 生成Stream流
      • 执行中间操作
        • 执行终止操作
        • 3.使用示例(中间操作)
          • 使用filter方法过滤所有红色苹果
            • 使用map方法,将所有苹果重量+10,并且输出对应的苹果的产地
              • sorted 排序方法
                • flatMap的使用
                  • 去重,合并,跳过,截取(concat,distinct,skip,limit)
                  • 终止操作
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档