Java基础之stream流最新版,stream流的基本操作

简介: Java基础之stream流最新版,stream流的基本操作

1. Stream流是什么?

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

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

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流的方式有三种,分别是

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 四个属性。

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方法
}
  1. 使用filter方法过滤所有红色苹果
//1.filter(过滤)筛选出所有颜色是红色的苹果
    List<Apple> red = appleList.stream().filter(apple -> apple.getColor().equals("red")).collect(Collectors.toList());
  1. 使用map方法,将所有苹果重量+10,并且输出对应的苹果的产地
//2.map的使用,将所有苹果重量+10,并且输出对应的苹果的产地
appleList.stream()
                .map(apple -> {
                    apple.setWeight(apple.getWeight() + 10);
                    return apple;
                }).map(Apple::getDistrict)
                .collect(Collectors.toList());
  1. sorted 排序方法
  • sorted():自然排序,流中元素需实现Comparable接口
  • sorted(Comparator com):Comparator排序器自定义排序
//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());
  1. flatMap的使用
  • 当使用map()操作时,不是返回一个值,而是返回一个集合或者一个数组的时候,这时候就可以使用flatMap解决这个问题。就是扁平化将每个元素映射成另一个Stream对象。
  1. ,将两个字符数组合并成一个新的字符数组
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);
  1. 去重,合并,跳过,截取(concat,distinct,skip,limit)
//创建两个流
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());
  1. 终止操作
  1. 聚合(max、min、count)
//取出价格最高的苹果
appleList.stream().max(Comparator.comparing(Apple::getPrice)).get();
//取出价格最低的苹果
appleList.stream().min(Comparator.comparing(Apple::getPrice)).get();
//统计元素个数
appleList.stream().count();
  1. 统计(counting、averaging)Collectors提供了一系列用于数据统计的静态方法:
  • 计数: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());
  1. 遍历/匹配(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"));
  1. 归集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());
  1. 分区、分组(partitioningBy、groupingBy)
  • 分区:将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()));
  1. 拼接(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]

List<String> arrayList = Arrays.asList("1","2","3","4");
        String collect = arrayList.stream().collect(Collectors.joining(",", "[", "]"));

目录
打赏
0
0
0
0
64
分享
相关文章
|
8月前
|
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
209 0
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
139 6
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
Java Stream 使用指南
本文介绍了Java中Stream流的使用方法,包括如何创建Stream流、中间操作(如map、filter、sorted等)和终结操作(如collect、forEach等)。此外,还讲解了并行流的概念及其可能带来的线程安全问题,并给出了示例代码。
262 0
|
6月前
|
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
79 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
56 1
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
5月前
|
Java中的Lambda表达式与Stream API的高效结合####
探索Java编程中Lambda表达式与Stream API如何携手并进,提升数据处理效率,实现代码简洁性与功能性的双重飞跃。 ####
59 0
|
7月前
|
Java——Stream流详解
Stream流是JDK 8引入的概念,用于高效处理集合或数组数据。其API支持声明式编程,操作分为中间操作和终端操作。中间操作包括过滤、映射、排序等,可链式调用;终端操作则完成数据处理,如遍历、收集等。Stream流简化了集合与数组的操作,提升了代码的简洁性
444 11
|
7月前
|
Java 8 Stream Api 中的 peek 操作
本文介绍了Java中`Stream`的`peek`操作,该操作通过`Consumer&lt;T&gt;`函数消费流中的每个元素,但不改变元素类型。文章详细解释了`Consumer&lt;T&gt;`接口及其使用场景,并通过示例代码展示了`peek`操作的应用。此外,还对比了`peek`与`map`的区别,帮助读者更好地理解这两种操作的不同用途。作者为码农小胖哥,原文发布于稀土掘金。
282 9
Java 8 Stream Api 中的 peek 操作