Java Stream创建
Java Stream创建[编辑 | 编辑源代码]
Java Stream API 是 Java 8 引入的一个强大的数据处理工具,它允许开发者以声明式的方式对集合数据进行高效、并行化的操作。Stream 本身并不是数据结构,而是一种对数据源(如集合、数组或 I/O 资源)进行高效聚合操作(如过滤、映射、排序等)的抽象。本节将详细介绍如何创建 Java Stream。
简介[编辑 | 编辑源代码]
Java Stream 提供了一种流式处理数据的方式,可以极大简化集合操作代码。Stream 的主要特点包括:
- 惰性求值:许多 Stream 操作(如过滤、映射)是惰性的,只有在终端操作触发时才会执行。
- 不可重用:Stream 只能被消费一次,再次使用会抛出异常。
- 并行处理:可以轻松实现并行操作以提高性能。
Stream 的创建方式[编辑 | 编辑源代码]
Java 提供了多种方式来创建 Stream,下面是最常用的几种方法。
1. 从集合创建[编辑 | 编辑源代码]
最常用的方式是从现有的集合(如 List 或 Set)创建 Stream。所有集合类都实现了 `Collection` 接口,该接口提供了 `stream()` 和 `parallelStream()` 方法。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamCreation {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 创建顺序流
Stream<String> stream = names.stream();
stream.forEach(System.out::println);
// 创建并行流
Stream<String> parallelStream = names.parallelStream();
parallelStream.forEach(System.out::println);
}
}
输出:
Alice Bob Charlie Charlie Bob Alice
注意并行流的输出顺序可能不同,因为元素是并行处理的。
2. 从数组创建[编辑 | 编辑源代码]
可以使用 `Arrays.stream()` 方法从数组创建 Stream:
import java.util.Arrays;
import java.util.stream.Stream;
public class ArrayToStream {
public static void main(String[] args) {
String[] languages = {"Java", "Python", "JavaScript"};
// 创建流
Stream<String> stream = Arrays.stream(languages);
stream.forEach(System.out::println);
// 也可以指定范围
Stream<String> partialStream = Arrays.stream(languages, 1, 3);
partialStream.forEach(System.out::println);
}
}
输出:
Java Python JavaScript Python JavaScript
3. 使用 Stream.of()[编辑 | 编辑源代码]
`Stream` 类提供了静态方法 `of()` 可以直接创建流:
import java.util.stream.Stream;
public class StreamOfExample {
public static void main(String[] args) {
Stream<String> stream = Stream.of("Apple", "Banana", "Orange");
stream.forEach(System.out::println);
// 也可以用于基本类型
Stream<Integer> numberStream = Stream.of(1, 2, 3, 4, 5);
numberStream.forEach(System.out::println);
}
}
输出:
Apple Banana Orange 1 2 3 4 5
4. 使用 Stream.generate()[编辑 | 编辑源代码]
`Stream.generate()` 方法接受一个 `Supplier` 函数式接口,可以生成无限流:
import java.util.stream.Stream;
public class StreamGenerate {
public static void main(String[] args) {
// 生成随机数流
Stream<Double> randomStream = Stream.generate(Math::random);
// 限制前5个元素
randomStream.limit(5).forEach(System.out::println);
}
}
输出(示例):
0.123456789 0.987654321 0.555555555 0.111111111 0.999999999
5. 使用 Stream.iterate()[编辑 | 编辑源代码]
`Stream.iterate()` 方法可以创建基于初始值和一元操作符的无限流:
import java.util.stream.Stream;
public class StreamIterate {
public static void main(String[] args) {
// 创建从0开始,每次加2的无限流
Stream<Integer> evenNumbers = Stream.iterate(0, n -> n + 2);
// 取前10个偶数
evenNumbers.limit(10).forEach(System.out::println);
}
}
输出:
0 2 4 6 8 10 12 14 16 18
Java 9 对 `iterate()` 进行了增强,可以添加终止条件:
Stream.iterate(0, n -> n < 100, n -> n + 2).forEach(System.out::println);
6. 从文件创建[编辑 | 编辑源代码]
可以使用 `Files.lines()` 方法从文件创建流:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
public class FileToStream {
public static void main(String[] args) {
try (Stream<String> lines = Files.lines(Paths.get("data.txt"))) {
lines.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}
7. 基本类型流[编辑 | 编辑源代码]
Java 为基本类型提供了专门的流类(`IntStream`、`LongStream`、`DoubleStream`),可以避免自动装箱的开销:
import java.util.stream.IntStream;
public class PrimitiveStream {
public static void main(String[] args) {
// 创建范围流
IntStream.range(1, 5).forEach(System.out::println);
// 创建包含结束值的范围流
IntStream.rangeClosed(1, 5).forEach(System.out::println);
}
}
输出:
1 2 3 4 1 2 3 4 5
流操作的生命周期[编辑 | 编辑源代码]
Java Stream 的操作分为两类: 1. 中间操作(Intermediate Operations):返回新的流,可以链式调用(如 `filter()`, `map()`) 2. 终端操作(Terminal Operations):触发流的执行并关闭流(如 `forEach()`, `collect()`)
实际应用案例[编辑 | 编辑源代码]
假设我们需要从一个员工列表中找出所有工资高于平均工资的 Java 开发人员:
import java.util.Arrays;
import java.util.List;
class Employee {
String name;
String role;
double salary;
Employee(String name, String role, double salary) {
this.name = name;
this.role = role;
this.salary = salary;
}
// Getters 省略...
}
public class StreamRealWorldExample {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", "Java Developer", 85000),
new Employee("Bob", "Python Developer", 75000),
new Employee("Charlie", "Java Developer", 90000),
new Employee("David", "Manager", 120000),
new Employee("Eve", "Java Developer", 80000)
);
// 计算平均工资
double averageSalary = employees.stream()
.mapToDouble(e -> e.salary)
.average()
.orElse(0);
System.out.println("Average salary: " + averageSalary);
// 找出高于平均工资的Java开发人员
employees.stream()
.filter(e -> "Java Developer".equals(e.role))
.filter(e -> e.salary > averageSalary)
.forEach(e -> System.out.println(e.name + ": " + e.salary));
}
}
输出:
Average salary: 90000.0 Alice: 85000 Charlie: 90000 Eve: 80000
性能考虑[编辑 | 编辑源代码]
- 对于小数据集,顺序流通常足够
- 对于大数据集,考虑使用并行流(`parallelStream()`)
- 避免在流中执行耗时操作(如I/O)
- 基本类型流(`IntStream`等)比对象流(`Stream<Integer>`)更高效
常见问题[编辑 | 编辑源代码]
Q: Stream 可以重复使用吗? A: 不可以。Stream 只能被消费一次,再次使用会抛出 `IllegalStateException`。
Q: 何时使用并行流? A: 当处理大量数据且操作可以并行化时,但要注意线程安全问题。
Q: Stream 和集合有什么区别? A: 集合主要关注数据存储,而 Stream 关注数据计算。集合是内存中的数据结构,Stream 不是。
总结[编辑 | 编辑源代码]
Java Stream 提供了多种创建方式,可以适应不同的数据源需求。理解如何创建 Stream 是使用 Stream API 的第一步。后续可以结合各种中间操作和终端操作,构建强大的数据处理流水线。对于初学者,建议从简单的集合流开始练习,逐步掌握更复杂的创建方式。