Stream流

Stream流

  • 1.Stream的特性
  • 2.Stream操作步骤
    • [2.1 创建Stream](#2.1 创建Stream)
    • [2.2 中间操作](#2.2 中间操作)
      • [2.2.1 筛选操作](#2.2.1 筛选操作)
      • [2.2.2 映射操作](#2.2.2 映射操作)
      • [2.2.3 排序操作](#2.2.3 排序操作)
      • [2.2.4 拆分与匹配操作](#2.2.4 拆分与匹配操作)
      • [2.2.5 映射到不同类型](#2.2.5 映射到不同类型)
    • [2.3 终端操作](#2.3 终端操作)
      • [2.3.1 迭代操作](#2.3.1 迭代操作)
      • [2.3.2 收集操作](#2.3.2 收集操作)
      • [2.3.3 归约操作](#2.3.3 归约操作)
      • [2.3.4 匹配操作](#2.3.4 匹配操作)
      • [2.3.5 查找操作](#2.3.5 查找操作)
      • [2.3.6 最值操作](#2.3.6 最值操作)
      • [2.3.7 转换操作](#2.3.7 转换操作)

1.Stream的特性

  • 不存储数据
    Stream不是一个数据存储的结构,它不会存储元素,而是通过管道将数据源的元素传递给操作。
  • 不可变性
    Stream不会修改源数据,例如filter不会将数据源中的数据删除,每次操作会生成一个新的Stream。
  • 惰性求值
    Stream的中间操作是延迟执行的,只有在遇到终端操作时才会执行。
  • 只能遍历一次
    Stream的元素只能访问一次,类似Iterator,操作没有回头路,如果你想从头重新访问流的元素,对不起,你得重新生成一个新的流。

Stream就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。

2.Stream操作步骤

  1. 创建Stream
    可以通过集合、数组、文件、函数等创建 Stream。
  2. 中间操作
    中间操作用于将一个Stream转换成另一个Stream。它们是惰性求值的,也就是说只有在终端操作出现时才会执行。
  3. 终止操作
    终端操作会触发Stream的实际计算,返回一个具体的结果或副作用。

2.1 创建Stream

  • 通过集合创建
  • 通过数组创建
  • 通过值创建
  • 通过方法创建
  • 从文件中获得

1.通过集合创建

  • stream() : 返回一个顺序流
  • parallelStream(): 返回一个并行流

顺序流

stream() 创建的是顺序流。在顺序流中,所有的操作都是按顺序执行的,即每个元素依次通过流的操作链。stream() 使用单线程处理数据,所有操作都是在同一个线程中按顺序进行。

java 复制代码
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream().forEach(System.out::println);

>>> 1 2 3 4 5(按顺序输出)

顺序流适合数据量较小或者不需要并行处理的场景。

并行流

parallelStream() 创建的是并行流。在并行流中,流中的元素可以被分成多个数据块,每个块由不同的线程并行处理。多线程执行:并行流会利用多个CPU核心进行并发处理,可以显著提高处理大数据集的性能。

java 复制代码
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.parallelStream().forEach(System.out::println);

>>> 5 1 3 2 4 (可能是任意顺序,因为是并行执行)

并行流适合大数据量和 CPU 密集型的任务,它能够有效地利用多核 CPU 的计算能力。但并行流也有开销,如线程创建和线程调度,适合在大数据量处理时使用。

注意事项

  • 并行流不适合所有场景,例如当你的操作对顺序有严格要求时(如累加、合并等),并行流可能产生错误的结果。
  • 并行流的多线程操作可能会引发线程安全问题,尤其是在处理共享资源时,需要特别注意线程同步。

2.通过数组创建

能够处理对应基本类型的数组IntStream、LongStream、DoubleStream :

java 复制代码
Arrays.stream(new int[]{1,2,3})

3.由值创建流

java 复制代码
Stream<Integer> integerStream = Stream.of(1);
Stream<String> stringStream = Stream.of("1");

2.2 中间操作

这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。

2.2.1 筛选操作

  • filter(Predicate<? super T> predicate)
    根据指定的条件过滤元素,保留符合条件的元素。
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .collect(Collectors.toList());
System.out.println(evenNumbers); // 输出: [2, 4, 6]
  • distinct()
    去除 Stream 中的重复元素,基于 equals() 方法进行比较。
java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Alice", "Charlie");
List<String> uniqueNames = names.stream()
                                .distinct()
                                .collect(Collectors.toList());
System.out.println(uniqueNames); // 输出: [Alice, Bob, Charlie]
  • limit(long maxSize)
    限制 Stream 中元素的数量,仅保留前 maxSize 个元素。
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> firstThree = numbers.stream()
                                  .limit(3)
                                  .collect(Collectors.toList());
System.out.println(firstThree); // 输出: [1, 2, 3]
  • skip(long n)
    跳过前 n 个元素,保留后续元素。
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> skipTwo = numbers.stream()
                               .skip(2)
                               .collect(Collectors.toList());
System.out.println(skipTwo); // 输出: [3, 4, 5]

2.2.2 映射操作

  • map(Function<? super T, ? extends R> mapper)
    将每个元素应用一个函数,将元素逐一映射成另一个值。
java 复制代码
List<String> words = Arrays.asList("hello", "world");
List<Integer> lengths = words.stream()
                            .map(String::length)
                            .collect(Collectors.toList());
System.out.println(lengths); // 输出: [5, 5]
  • flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
    将每个元素应用一个函数,将元素映射成一个新的流,然后将这些流"展平"或合并成一个流(一对多的映射)。
java 复制代码
List<List<String>> nestedList = Arrays.asList(
    Arrays.asList("a", "b"),
    Arrays.asList("c", "d"),
    Arrays.asList("e", "f")
);
List<String> flatList = nestedList.stream()
                                  .flatMap(List::stream)
                                  .collect(Collectors.toList());
System.out.println(flatList); // 输出: [a, b, c, d, e, f]

2.2.3 排序操作

  • sorted()
    按照自然顺序对元素进行排序。
java 复制代码
List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);
List<Integer> sortedNumbers = numbers.stream()
                                     .sorted()
                                     .collect(Collectors.toList());
System.out.println(sortedNumbers); // 输出: [1, 2, 3, 4, 5]
  • sorted(Comparator<? super T> comparator)
    按照自定义比较器对元素进行排序。
java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> sortedNames = names.stream()
                                .sorted(Comparator.reverseOrder())
                                .collect(Collectors.toList());
System.out.println(sortedNames); // 输出: [Charlie, Bob, Alice]

2.2.4 拆分与匹配操作

  • takeWhile(Predicate<? super T> predicate)
    从头开始保留满足条件的元素,一旦遇到第一个不满足条件的元素,终止处理。
java 复制代码
List<Integer> numbers = Arrays.asList(2, 4, 6, 1, 8, 10);
List<Integer> taken = numbers.stream()
                             .takeWhile(n -> n % 2 == 0)
                             .collect(Collectors.toList());
System.out.println(taken); // 输出: [2, 4, 6]
  • dropWhile(Predicate<? super T> predicate)
    跳过开头满足条件的元素,保留后续元素。
java 复制代码
List<Integer> numbers = Arrays.asList(2, 4, 6, 1, 8, 10);
List<Integer> dropped = numbers.stream()
                               .dropWhile(n -> n % 2 == 0)
                               .collect(Collectors.toList());
System.out.println(dropped); // 输出: [1, 8, 10]

2.2.5 映射到不同类型

  • mapToInt(ToIntFunction<? super T> mapper)
    将 Stream 元素映射为 IntStream。
java 复制代码
List<String> words = Arrays.asList("hello", "world");
IntStream lengths = words.stream()
                         .mapToInt(String::length);
lengths.forEach(System.out::println); // 输出: 5 5
  • mapToDouble(ToDoubleFunction<? super T> mapper)
    将 Stream 元素映射为 DoubleStream。
java 复制代码
List<String> words = Arrays.asList("hello", "world");
DoubleStream doubleLengths = words.stream()
                                  .mapToDouble(s -> (double) s.length());
doubleLengths.forEach(System.out::println); // 输出: 5.0 5.0
  • mapToLong(ToLongFunction<? super T> mapper)
    将 Stream 元素映射为 LongStream。
java 复制代码
List<String> words = Arrays.asList("hello", "world");
LongStream longLengths = words.stream()
                              .mapToLong(s -> (long) s.length());
longLengths.forEach(System.out::println); // 输出: 5 5

2.3 终端操作

2.3.1 迭代操作

  • forEach(): 对流中的每个元素执行指定的操作。
  • forEachOrdered(): 在有序流上以遇到的顺序对每个元素执行指定的操作(即使在并行流中也是如此)。
java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);  // 对每个元素执行操作

2.3.2 收集操作

  • collect()
    这些操作用于将流的结果收集到不同的容器或数据结构中(例如,List、Set、Map)。常与 Collectors 一起使用。
java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperNames = names.stream()
                               .map(String::toUpperCase)
                               .collect(Collectors.toList());  // 将结果收集为 List

2.3.3 归约操作

  • reduce()
    reduce() 是一个通用的归约操作,它将流中的元素通过累加器函数合并为一个结果值。通常用于聚合、求和、累积等操作。
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 使用有 identity 参数的 reduce
int sum = numbers.stream().reduce(0, Integer::sum);
System.out.println(sum);  // 输出: 15

// 使用没有 identity 的 reduce
Optional<Integer> sumWithoutIdentity = numbers.stream().reduce(Integer::sum);
sumWithoutIdentity.ifPresent(System.out::println);  // 输出: 15


List<String> words = Arrays.asList("Hello", "World", "Java");
String result = words.stream().reduce("", (a, b) -> a + " " + b);
System.out.println(result);  // 输出: " Hello World Java"
  • count()
    用于计算流中的元素总数。
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

// 统计大于 3 的元素个数
long countGreaterThanThree = numbers.stream().filter(n -> n > 3).count();
System.out.println(countGreaterThanThree);  // 输出: 3
  • summaryStatistics()
    summaryStatistics() 是一个用于数值流的终端操作,提供对流中元素的统计信息,例如最大值、最小值、总和、平均值和数量。常与 IntStream、LongStream 和 DoubleStream 一起使用。
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

// 使用 mapToInt 将 Integer 转为 int
IntSummaryStatistics stats = numbers.stream()
                                    .mapToInt(Integer::intValue)
                                    .summaryStatistics();

System.out.println("Max: " + stats.getMax());         // 输出: Max: 9
System.out.println("Min: " + stats.getMin());         // 输出: Min: 1
System.out.println("Sum: " + stats.getSum());         // 输出: Sum: 45
System.out.println("Average: " + stats.getAverage()); // 输出: Average: 5.0
System.out.println("Count: " + stats.getCount());     // 输出: Count: 9

2.3.4 匹配操作

  • anyMatch()
    判断流中的任意一个元素是否满足给定的条件。
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyMatch = numbers.stream().anyMatch(n -> n > 3);
System.out.println(anyMatch); // 输出: true
  • allMatch()
    判断流中的所有元素是否都满足给定的条件。
  • noneMatch()
    判断流中的所有元素是否都不满足给定的条件。

2.3.5 查找操作

  • findFirst()
    返回流中的第一个元素。
java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Optional<String> firstName = names.stream().findFirst();
firstName.ifPresent(System.out::println); // 输出: Alice
  • findAny()
    返回流中的任意一个元素,特别适用于并行流。在并行流中,findAny 可能比 findFirst 更高效,因为它可以直接返回找到的第一个可用结果。

2.3.6 最值操作

  • min()
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> min = numbers.stream().min(Integer::compareTo);
min.ifPresent(System.out::println); // 输出: 1
  • max()

2.3.7 转换操作

  • toArray()
    将流中的元素转换为数组。
java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
String[] namesArray = names.stream().toArray(String[]::new); // 转换为数组
System.out.println(Arrays.toString(namesArray)); // 输出: [Alice, Bob, Charlie]
相关推荐
繁依Fanyi22 分钟前
旅游心动盲盒:开启个性化旅行新体验
java·服务器·python·算法·eclipse·tomcat·旅游
不烦下雨c34 分钟前
[网络]抓包工具介绍 tcpdump
linux·tcpdump
satan–01 小时前
R语言的基本语句及基本规则
开发语言·windows·r语言
南瓜小米粥、1 小时前
通过fdisk初始化Linux数据盘
linux·运维·服务器
秋风起,再归来~1 小时前
【Linux庖丁解牛】—Linux基本指令(中)!
linux·指令
Eternal-Student1 小时前
预处理、编译、汇编、链接
linux·汇编·windows
LYK_HAHA2 小时前
centos常用知识和命令
linux·运维·centos
PythonFun3 小时前
自建RustDesk服务器:详细步骤与操作指南
运维·服务器
Android技术栈3 小时前
鸿蒙开发(NEXT/API 12)【管理应用与Wear Engine服务的连接状态】手机侧应用开发
服务器·harmonyos·鸿蒙·鸿蒙系统·openharmony