java Stream详解

简介: 【10月更文挑战第4天】

Java Stream API 是 Java 8 及以上版本中提供的一种新特性,用于简化数据处理和操作。Stream API 可以让你以声明式的方式处理数据集合(比如集合、数组等),支持顺序和并行处理。以下是 Java Stream 的一些核心原理和概念:

1. 流的组成

  • 数据源:流的来源,可以是集合、数组、文件等。
  • 中间操作:一个中间操作链,对数据源的数据进行处理。比如 filtermapsorted 等。
  • 终端操作:执行中间操作链,并产生结果。比如 collectforEachreduce 等。

    2. 流的操作类型

  • 中间操作:返回的是流本身,可以有一个或多个连续的中间操作,它们可以合并成一条流水线。中间操作是惰性的,只有在终端操作执行时,中间操作才会执行。
    • 无状态操作:比如 mapfilter,不依赖于之前元素的处理状态。
    • 有状态操作:比如 sorteddistinct,需要知道之前元素的处理状态。
  • 终端操作:返回的是一个结果或者一个副作用。比如 forEach 是一个副作用操作,因为它不会返回结果,而 collect 则会返回一个结果。

    3. 流的特性

  • 惰性求值:流在中间操作时不会执行任何处理,直到终端操作开始时,中间操作才会被执行。
  • 内部迭代:与外部迭代(比如 for 循环)不同,流的迭代是在内部进行的,用户不需要手动进行迭代。

    4. 流的实现原理

    流的实现依赖于以下几个核心组件:
  • :比如 Collection.stream() 方法产生流。
  • 数据传输:流操作如何将数据从源传递到终点。
  • 操作链:流操作如何链接在一起。
  • sink:终端操作的具体实现。
    当执行一个流操作时,通常发生以下步骤:
  1. 创建流:通过数据源,比如集合、数组等,来创建一个流。
  2. 构建操作链:通过一系列的中间操作来构建操作链。
  3. 触发终端操作:执行终端操作,这时中间操作会被依次执行。
  4. 生成结果:终端操作会生成最终的结果或者副作用。
    在内部实现上,流的操作通常使用一种“流水线”模式,数据像在流水线上一样被处理。每个中间操作返回一个新的流,这个流包含了上一个流以及一个新的操作。当执行终端操作时,这些操作会以某种方式组合起来,形成一个“操作图”,然后按照一定的顺序执行。
    并行流利用了 Java 7 引入的 Fork/Join 框架,通过递归地将任务分割成更小的任务,然后将每个子任务的结果合并起来,从而实现数据的并行处理。
    流的这些原理和特性使得它在处理集合数据时非常高效和方便,特别是在需要编写复杂的数据处理管道时。

Java Stream是Java 8引入的一个新的抽象层,它提供了一种新的方式来处理集合(如List、Set、Map等)。Stream允许你以声明式的方式处理数据,而不是以传统的迭代方式。这种声明式编程风格使得代码更加简洁、易于理解和维护。

Stream的三个阶段

  1. 创建Stream:通过集合的stream()方法或者通过Arrays.stream()方法来创建一个Stream。
  2. 中间操作:对Stream进行中间操作,比如过滤、映射、排序等。这些操作不会立即执行,而是会返回一个新的Stream。
  3. 终端操作:对Stream进行终端操作,比如计算、收集等。这些操作会立即执行,并返回一个结果。

    常用中间操作

  4. 过滤(Filter)filter(Predicate<? super T> predicate),通过指定条件过滤出满足条件的元素。
  5. 映射(Map)map(Function<? super T, ? extends U> mapper),将Stream中的每个元素通过映射函数转换成另一个元素。
  6. 排序(Sort)sorted(),对Stream中的元素进行排序。
  7. 筛选(Distinct)distinct(),去除Stream中的重复元素。
  8. 跳过(Skip)skip(long n),跳过Stream中前n个元素。
  9. 限制(Limit)limit(long n),限制Stream中元素的数量,只返回前n个元素。

    常用终端操作

  10. 收集(Collect)collect(Collector<? super T, A, R> collector),将Stream中的元素收集到集合、数组或其他形式的结果中。
  11. 计算(Count)count(),计算Stream中元素的数量。
  12. 遍历(ForEach)forEach(Consumer<? super T> action),对Stream中的每个元素执行指定的操作。
  13. 找到(FindFirst)findFirst(),返回Stream中的第一个元素。
  14. 找到(FindAny)findAny(),返回Stream中的任意一个元素。
  15. 最小值(Min)min(Comparator<? super T> comparator),返回Stream中的最小值。
  16. 最大值(Max)max(Comparator<? super T> comparator),返回Stream中的最大值。
  17. 并行流(Parallel)parallel(),将Stream转换为并行流,提高处理大量数据时的性能。

    示例代码

    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;
    public class StreamExample {
         
     public static void main(String[] args) {
         
         List<String> list = Arrays.asList("a", "b", "c", "d");
         // 创建Stream
         Stream<String> stream = list.stream();
         // 中间操作
         stream.filter(s -> s.startsWith("a"))
               .map(String::toUpperCase)
               .forEach(System.out::println);
         // 终端操作
         List<String> result = stream.collect(Collectors.toList());
         System.out.println(result);
     }
    }
    
    在这个例子中,我们首先创建了一个Stream,然后通过中间操作过滤出以"a"开头的字符串,并将其转换为大写。最后,我们通过终端操作将结果收集到一个List中。

    总结

    Java Stream提供了一种强大的、声明式的数据处理方式,它可以帮助我们写出更加简洁、高效的代码。然而,Stream的使用也需要一定的理解,尤其是在处理并发和异常处理时。在实际开发中,我们应该根据具体需求和场景选择合适的编程方式。
相关文章
|
4月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
123 0
|
1月前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
2月前
|
Java 流计算
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
44 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
|
2月前
|
Java Shell 流计算
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
25 1
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
|
3月前
|
存储 Java API
Java——Stream流详解
Stream流是JDK 8引入的概念,用于高效处理集合或数组数据。其API支持声明式编程,操作分为中间操作和终端操作。中间操作包括过滤、映射、排序等,可链式调用;终端操作则完成数据处理,如遍历、收集等。Stream流简化了集合与数组的操作,提升了代码的简洁性
138 11
Java——Stream流详解
|
2月前
|
存储 Java 数据处理
Flink-01 介绍Flink Java 3分钟上手 HelloWorld 和 Stream ExecutionEnvironment DataSet FlatMapFunction
Flink-01 介绍Flink Java 3分钟上手 HelloWorld 和 Stream ExecutionEnvironment DataSet FlatMapFunction
37 1
|
3月前
|
Java API C++
Java 8 Stream Api 中的 peek 操作
本文介绍了Java中`Stream`的`peek`操作,该操作通过`Consumer&lt;T&gt;`函数消费流中的每个元素,但不改变元素类型。文章详细解释了`Consumer&lt;T&gt;`接口及其使用场景,并通过示例代码展示了`peek`操作的应用。此外,还对比了`peek`与`map`的区别,帮助读者更好地理解这两种操作的不同用途。作者为码农小胖哥,原文发布于稀土掘金。
128 9
Java 8 Stream Api 中的 peek 操作
|
3月前
|
Java C# Swift
Java Stream中peek和map不为人知的秘密
本文通过一个Java Stream中的示例,探讨了`peek`方法在流式处理中的应用及其潜在问题。首先介绍了`peek`的基本定义与使用,并通过代码展示了其如何在流中对每个元素进行操作而不返回结果。接着讨论了`peek`作为中间操作的懒执行特性,强调了如果没有终端操作则不会执行的问题。文章指出,在某些情况下使用`peek`可能比`map`更简洁,但也需注意其懒执行带来的影响。
163 2
Java Stream中peek和map不为人知的秘密
|
3月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
219 12
|
3月前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的探索
【9月更文挑战第24天】本文将深入浅出地介绍Java 8中的重要新特性——Lambda表达式和Stream API,通过实例解析其语法、用法及背后的设计哲学。我们将一探究竟,看看这些新特性如何让Java代码变得更加简洁、易读且富有表现力,同时提升程序的性能和开发效率。