当前位置: 首页 > news >正文

Java 8 Stream 流详细教程 - 全面指南

目录

​​​​​​

Stream 基础概念

Stream 的创建方式

中间操作详解

1. filter() - 过滤

2. map() - 映射转换

3. flatMap() - 扁平化映射

4. distinct() - 去重

5. sorted() - 排序

6. peek() - 查看元素

7. limit() - 限制元素数量

8. skip() - 跳过元素

9. takeWhile() 和 dropWhile() (Java 9+)

终端操作详解

1. forEach() 和 forEachOrdered()

2. collect() - 收集结果

3. reduce() - 归约操作

4. 匹配操作

5. 查找操作

6. min() 和 max()

7. count()

收集器 Collectors

1. 基本收集器

2. 分组收集器

3. 分区收集器

4. 字符串收集器

5. 数值收集器

6. 自定义收集器

并行流 Parallel Streams

1. 创建并行流

2. 并行流操作示例

3. 自定义线程池

4. 并行流的注意事项

5. 性能考虑

原始类型流

1. IntStream

2. LongStream

3. DoubleStream

4. 原始类型流的转换

实际应用案例

性能优化和注意事项

最佳实践

总结


Stream 基础概念

什么是 Stream?

Stream 是 Java 8 引入的一个新的抽象概念,用于以声明式方式处理数据集合。Stream 不是数据结构,它不会存储元素,而是按需计算。

Stream 的特点:

  • 不存储数据:Stream 不是数据结构,不会存储元素
  • 函数式编程:Stream 的操作不会修改原始数据源
  • 惰性求值:中间操作都是惰性的,只有在终端操作执行时才会进行计算
  • 可消费性:Stream 只能被消费一次

Stream 操作分类

// Stream 操作分为两类:// 1. 中间操作(Intermediate Operations)- 返回一个新的 Stream
// filter, map, flatMap, distinct, sorted, peek, limit, skip// 2. 终端操作(Terminal Operations)- 产生结果或副作用
// forEach, collect, reduce, count, anyMatch, allMatch, noneMatch, 
// findFirst, findAny, min, max

Stream 的创建方式

1. 从集合创建

import java.util.*;
import java.util.stream.*;// 从 List 创建
List<String> list = Arrays.asList("apple", "banana", "cherry");
Stream<String> stream1 = list.stream();
Stream<String> parallelStream1 = list.parallelStream();// 从 Set 创建
Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Stream<Integer> stream2 = set.stream();// 从 Map 创建
Map<String, Integer> map = new HashMap<>();
map.put("apple", 5);
map.put("banana", 3);Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();

2. 从数组创建

// 使用 Arrays.stream()
String[] array = {"apple", "banana", "cherry"};
Stream<String> stream3 = Arrays.stream(array);// 指定范围
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
IntStream stream4 = Arrays.stream(numbers, 2, 5); // [3, 4, 5]// 直接从可变参数创建
Stream<String> stream5 = Stream.of("apple", "banana", "cherry");

3. 使用 Stream 构建器

// 使用 Stream.builder()
Stream<String> stream6 = Stream.<String>builder().add("apple").add("banana").add("cherry").build();// 空 Stream
Stream<String> emptyStream = Stream.empty();// 单元素 Stream
Stream<String> singleStream = Stream.of("apple");

4. 生成无限流

// 使用 generate() 生成无限流
Stream<Double> randomStream = Stream.generate(Math::random);
Stream<String> constantStream = Stream.generate(() -> "Hello");// 使用 iterate() 生成序列
Stream<Integer> evenNumbers = Stream.iterate(0, n -> n + 2);
Stream<Integer> fibonacci = Stream.iterate(new int[]{0, 1}, arr -> new int[]{arr[1], arr[0] + arr[1]}).mapToInt(arr -> arr[0]);// Java 9+ 带条件的 iterate
Stream<Integer> limitedNumbers = Stream.iterate(1, n -> n <= 100, n -> n + 1);

5. 从文件创建

import java.nio.file.*;try {// 读取文件行Stream<String> lines = Files.lines(Paths.get("data.txt"));// 遍历目录Stream<Path> paths = Files.walk(Paths.get("src"));// 查找文件Stream<Path> found = Files.find(Paths.get("src"), Integer.MAX_VALUE,(path, attr) -> path.toString().endsWith(".java"));} catch (IOException e) {e.printStackTrace();
}

6. 从其他源创建

// 从字符串创建字符流
IntStream charStream = "Hello".chars();// 从范围创建
IntStream range1 = IntStream.range(1, 10);        // [1, 2, ..., 9]
IntStream range2 = IntStream.rangeClosed(1, 10);  // [1, 2, ..., 10]// 从 Optional 创建
Optional<String> optional = Optional.of("Hello");
Stream<String> optionalStream = optional.stream(); // Java 9+// 从正则表达式创建
Pattern pattern = Pattern.compile(",");
Stream<String> splitStream = pattern.splitAsStream("a,b,c,d");

中间操作详解

中间操作返回一个新的 Stream,支持链式调用,并且是惰性的。

1. filter() - 过滤

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 过滤偶数
List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
// 结果: [2, 4, 6, 8, 10]// 过滤字符串
List<String> words = Arrays.asList("apple", "banana", "cherry", "date");
List<String> longWords = words.stream().filter(word -> word.length() > 5).collect(Collectors.toList());
// 结果: ["banana", "cherry"]// 过滤 null 值
List<String> stringsWithNull = Arrays.asList("apple", null, "banana", null, "cherry");
List<String> nonNullStrings = stringsWithNull.stream().filter(Objects::nonNull).collect(Collectors.toList());
// 结果: ["apple", "banana", "cherry"]// 复杂条件过滤
List<Person> people = Arrays.asList(new Person("Alice", 25, "Engineer"),new Person("Bob", 30, "Designer"),new Person("Charlie", 35, "Engineer"),new Person("Diana", 28, "Manager")
);List<Person> youngEngineers = people.stream().filter(person -> person.getAge() < 30 && "Engineer".equals(person.getJob())).collect(Collectors.toList());

2. map() - 映射转换

// 基本映射
List<String> words = Arrays.asList("apple", "banana", "cherry");
List<Integer> lengths = words.stream().map(String::length).collect(Collectors.toList());
// 结果: [5, 6, 6]// 转换为大写
List<String> upperCaseWords = words.stream().map(String::toUpperCase).collect(Collectors.toList());
// 结果: ["APPLE", "BANANA", "CHERRY"]// 数学运算
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squares = numbers.stream().map(n -> n * n).collect(Collectors.toList());
// 结果: [1, 4, 9, 16, 25]// 对象属性映射
List<Person> people = Arrays.asList(new Person("Alice", 25, "Engineer"),new Person("Bob", 30, "Designer")
);List<String> names = people.stream().map(Person::getName).collect(Collectors.toList());
// 结果: ["Alice", "Bob"]// 复杂对象转换
List<PersonDTO> personDTOs = people.stream().map(person -> new PersonDTO(person.getName().toUpperCase(),person.getAge(),person.getJob())).collect(Collectors.toList());// 链式映射
List<String> processedNames = people.stream().map(Person::getName).map(String::toUpperCase).map(name -> "Mr/Ms. " + name).collect(Collectors.toList());

3. flatMap() - 扁平化映射

// 扁平化字符串列表
List<List<String>> listOfLists = Arrays.asList(Arrays.asList("apple", "banana"),Arrays.asList("cherry", "date"),Arrays.asList("elderberry", "fig")
);List<String> flatList = listOfLists.stream().flatMap(Collection::stream).collect(Collectors.toList());
// 结果: ["apple", "banana", "cherry", "date", "elderberry", "fig"]// 将字符串分割并扁平化
List<String> sentences = Arrays.asList("Hello World","Java Stream","Functional Programming"
);List<String> words = sentences.stream().flatMap(sentence -> Arrays.stream(sentence.split(" "))).collect(Collectors.toList());
// 结果: ["Hello", "World", "Java", "Stream", "Functional", "Programming"]// 处理嵌套对象
class Department {private String name;private List<Person> employees;// 构造器和getter方法
}List<Department> departments = Arrays.asList(new Department("IT", Arrays.asList(new Person("Alice", 25, "Engineer"),new Person("Bob", 30, "Designer"))),new Department("HR", Arrays.asList(new Person("Charlie", 35, "Manager"),new Person("Diana", 28, "Recruiter")))
);List<Person> allEmployees = departments.stream().flatMap(dept -> dept.getEmployees().stream()).collect(Collectors.toList());// 扁平化 Optional
List<Optional<String>> optionals = Arrays.asList(Optional.of("apple"),Optional.empty(),Optional.of("banana"),Optional.empty(),Optional.of("cherry")
);List<String> presentValues = optionals.stream().flatMap(Optional::stream) // Java 9+.collect(Collectors.toList());
// 结果: ["apple", "banana", "cherry"]// 自定义扁平化
List<String> phoneNumbers = people.stream().flatMap(person -> person.getPhoneNumbers().stream()).collect(Collectors.toList());

4. distinct() - 去重

// 基本去重
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4, 5, 5);
List<Integer> distinctNumbers = numbers.stream().distinct().collect(Collectors.toList());
// 结果: [1, 2, 3, 4, 5]// 字符串去重
List<String> words = Arrays.asList("apple", "banana", "apple", "cherry", "banana");
List<String> distinctWords = words.stream().distinct().collect(Collectors.toList());
// 结果: ["apple", "banana", "cherry"]// 对象去重(需要重写 equals 和 hashCode)
List<Person> people = Arrays.asList(new Person("Alice", 25, "Engineer"),new Person("Bob", 30, "Designer"),new Person("Alice", 25, "Engineer"), // 重复new Person("Charlie", 35, "Manager")
);List<Person> distinctPeople = people.stream().distinct().collect(Collectors.toList());// 根据特定属性去重
List<Person> distinctByName = people.stream().collect(Collectors.toMap(Person::getName,Function.identity(),(existing, replacement) -> existing)).values().stream().collect(Collectors.toList());// 使用自定义比较器去重
List<Person> distinctByAge = people.stream().collect(Collectors.groupingBy(Person::getAge)).values().stream().map(group -> group.get(0)) // 取每组的第一个.collect(Collectors.toList());

5. sorted() - 排序

// 自然排序
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
List<Integer> sortedNumbers = numbers.stream().sorted().collect(Collectors.toList());
// 结果: [1, 1, 2, 3, 4, 5, 6, 9]// 字符串排序
List<String> words = Arrays.asList("banana", "apple", "cherry", "date");
List<String> sortedWords = words.stream().sorted().collect(Collectors.toList());
// 结果: ["apple", "banana", "cherry", "date"]// 逆序排序
List<Integer> reverseSorted = numbers.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());// 按字符串长度排序
List<String> sortedByLength = words.stream().sorted(Comparator.comparing(String::length)).collect(Collectors.toList());// 对象排序
List<Person> people = Arrays.asList(new Person("Alice", 25, "Engineer"),new Person("Bob", 30, "Designer"),new Person("Charlie", 20, "Intern")
);// 按年龄排序
List<Person> sortedByAge = people.stream().sorted(Comparator.comparing(Person::getAge)).collect(Collectors.toList());// 按姓名排序
List<Person> sortedByName = people.stream().sorted(Comparator.comparing(Person::getName)).collect(Collectors.toList());// 多级排序
List<Person> multiSorted = people.stream().sorted(Comparator.comparing(Person::getJob).thenComparing(Person::getAge).thenComparing(Person::getName)).collect(Collectors.toList());// 自定义排序
List<Person> customSorted = people.stream().sorted((p1, p2) -> {int jobCompare = p1.getJob().compareTo(p2.getJob());if (jobCompare != 0) return jobCompare;return Integer.compare(p2.getAge(), p1.getAge()); // 年龄降序}).collect(Collectors.toList());// null 值处理
List<String> wordsWithNull = Arrays.asList("banana", null, "apple", "cherry");
List<String> sortedWithNullFirst = wordsWithNull.stream().sorted(Comparator.nullsFirst(String::compareTo)).collect(Collectors.toList());List<String> sortedWithNullLast = wordsWithNull.stream().sorted(Comparator.nullsLast(String::compareTo)).collect(Collectors.toList());

6. peek() - 查看元素

List<String> words = Arrays.asList("apple", "banana", "cherry");// 调试用 peek
List<String> result = words.stream().peek(word -> System.out.println("Processing: " + word)).filter(word -> word.length() > 5).peek(word -> System.out.println("After filter: " + word)).map(String::toUpperCase).peek(word -> System.out.println("After map: " + word)).collect(Collectors.toList());// 副作用操作(不推荐,但有时有用)
List<String> processed = new ArrayList<>();
List<String> result2 = words.stream().peek(processed::add) // 将元素添加到另一个列表.filter(word -> word.startsWith("a")).collect(Collectors.toList());// 计数器示例
AtomicInteger counter = new AtomicInteger(0);
List<String> result3 = words.stream().peek(word -> counter.incrementAndGet()).collect(Collectors.toList());
System.out.println("Processed " + counter.get() + " elements");// 日志记录
List<Person> people = Arrays.asList(new Person("Alice", 25, "Engineer"),new Person("Bob", 30, "Designer")
);List<Person> adults = people.stream().peek(person -> logger.debug("Processing person: {}", person.getName())).filter(person -> person.getAge() >= 18).peek(person -> logger.info("Adult found: {}", person.getName())).collect(Collectors.toList());

7. limit() - 限制元素数量

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 取前5个元素
List<Integer> first5 = numbers.stream().limit(5).collect(Collectors.toList());
// 结果: [1, 2, 3, 4, 5]// 结合其他操作
List<Integer> first3Even = numbers.stream().filter(n -> n % 2 == 0).limit(3).collect(Collectors.toList());
// 结果: [2, 4, 6]// 无限流的限制
List<Double> randomNumbers = Stream.generate(Math::random).limit(5).collect(Collectors.toList());// 斐波那契数列前10项
List<Integer> fibonacci = Stream.iterate(new int[]{0, 1}, arr -> new int[]{arr[1], arr[0] + arr[1]}).mapToInt(arr -> arr[0]).limit(10).boxed().collect(Collectors.toList());
// 结果: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]// 分页效果
int pageSize = 3;
int pageNumber = 2; // 第2页(从0开始)List<String> words = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j");
List<String> page = words.stream().skip(pageNumber * pageSize).limit(pageSize).collect(Collectors.toList());
// 结果: ["g", "h", "i"]

8. skip() - 跳过元素

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 跳过前3个元素
List<Integer> afterSkip = numbers.stream().skip(3).collect(Collectors.toList());
// 结果: [4, 5, 6, 7, 8, 9, 10]// 结合 limit 实现分页
List<Integer> page2 = numbers.stream().skip(3).limit(3).collect(Collectors.toList());
// 结果: [4, 5, 6]// 跳过偶数后的前3个奇数
List<Integer> oddAfterSkip = numbers.stream().filter(n -> n % 2 == 1).skip(2).limit(3).collect(Collectors.toList());
// 结果: [5, 7, 9]// 处理大数据集的分批处理
List<String> largeDataset = Arrays.asList("item1", "item2", /*... 更多数据*/);
int batchSize = 100;
int batchNumber = 5;List<String> batch = largeDataset.stream().skip(batchNumber * batchSize).limit(batchSize).collect(Collectors.toList());// 移除文件头部行
List<String> csvLines = Arrays.asList("Name,Age,Job",           // 头部行"Alice,25,Engineer","Bob,30,Designer","Charlie,35,Manager"
);List<String> dataLines = csvLines.stream().skip(1) // 跳过头部行.collect(Collectors.toList());

9. takeWhile() 和 dropWhile() (Java 9+)

// takeWhile - 取元素直到条件为false
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 4, 3, 2, 1);List<Integer> ascending = numbers.stream().takeWhile(n -> n < 5).collect(Collectors.toList());
// 结果: [1, 2, 3, 4]// dropWhile - 丢弃元素直到条件为false
List<Integer> afterDrop = numbers.stream().dropWhile(n -> n < 5).collect(Collectors.toList());
// 结果: [5, 4, 3, 2, 1]// 处理有序数据
List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");List<String> shortWords = words.stream().takeWhile(word -> word.length() <= 6).collect(Collectors.toList());
// 结果: ["apple", "banana", "cherry"]// 处理日志文件
List<String> logLines = Arrays.asList("2023-01-01 INFO Starting application","2023-01-01 DEBUG Loading configuration","2023-01-01 ERROR Database connection failed","2023-01-02 INFO Application restarted","2023-01-02 DEBUG Processing requests"
);List<String> firstDayLogs = logLines.stream().takeWhile(line -> line.startsWith("2023-01-01")).collect(Collectors.toList());

终端操作详解

终端操作会触发流的执行,并产生最终结果。

1. forEach() 和 forEachOrdered()

List<String> words = Arrays.asList("apple", "banana", "cherry");// 基本遍历
words.stream().forEach(System.out::println);// 带索引的遍历
AtomicInteger index = new AtomicInteger(0);
words.stream().forEach(word -> {System.out.println(index.getAndIncrement() + ": " + word);});// 执行副作用操作
List<String> processed = new ArrayList<>();
words.stream().map(String::toUpperCase).forEach(processed::add);// 并行流中保证
http://www.xdnf.cn/news/989677.html

相关文章:

  • 重塑未来的力量:人工智能的技术演进与产业变革
  • git的5种分支分别是干嘛的,git常用指令
  • git的常用方法
  • 交换机上抓包
  • 大模型与人工智能
  • 了解shell中的Fork炸弹
  • Java并发编程实战 Day 17:CompletableFuture高级应用
  • 种子音乐携手RBW 精心打造Solar颂乐首支中文单曲《Floating Free》
  • 单端的时钟阻抗设置为50欧姆,差分的时钟阻抗设置为100欧姆
  • echarts 地图 海南省全岛完整展示
  • Vuex 中Mutation 和Action介绍
  • Android SDK Manager 2025镜像,亲测好用
  • Windows为何总在不停更新补丁
  • EtherCAT转CANopen网关实现与伺服系统连通的配置实例探究
  • linux虚拟机磁盘容量不足?一个指令解决问题
  • 国内各种AI工具库
  • 大模型笔记_检索增强生成(RAG)
  • ABC 337
  • Arduino入门教程:0、课程介绍认识Arduino
  • 餐厅商家怎么做元宵节活动宣传海报?
  • C++ 精简知识点
  • 推荐算法介绍-基础算法
  • python打卡第49天
  • Unity | AmplifyShaderEditor插件基础(第九集:旗子进阶版)
  • Nginx完全学习指南 - 从入门到实战
  • xilinx的GT配置说明(一)
  • Barcode解码 一维码、二维码识别 物流单号识别
  • Flink 系列之二十六 - Flink SQL - 中间算子:普通聚合
  • QDockWidget
  • Spring Data MongoDB 技术指南