在 Java中,常见的创建 Stream 的方式有哪些?
在 Java 中,创建 Stream(流)的方法非常多样,可以根据不同的数据源(集合、数组、I/O 通道、产生器等)来选择。
以下是 Java 中最常见的几种创建 Stream 的方式:
1. 通过集合(Collection)创建(最常用)
Java 的 Collection 接口在 Java 8 中新增了 stream() 和 parallelStream() 方法,几乎所有的集合类(如 List、Set)都可以直接调用这两个方法来创建流。
stream():创建一个顺序流。parallelStream():创建一个并行流(多线程处理)。
java
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
// 1. 创建顺序流
Stream<String> stream = list.stream();
// 2. 创建并行流
Stream<String> parallelStream = list.parallelStream();
2. 通过数组创建
可以使用 Arrays.stream() 静态方法,或者使用 Stream.of() 方法将数组转化为流。
java
String[] array = {"Java", "Python", "C++"};
// 1. 使用 Arrays.stream()
Stream<String> stream1 = Arrays.stream(array);
// 2. 也可以指定范围 (前闭后开区间:[1, 3))
Stream<String> streamSub = Arrays.stream(array, 1, 3);
3. 通过 Stream 类的静态工厂方法
Stream 接口自身提供了几个静态方法,用于直接生成流。
① Stream.of(T... values)
直接传入零个或多个元素。
java
Stream<String> stream = Stream.of("a", "b", "c");
② Stream.empty()
创建一个空的流。通常用于避免返回 null。
java
Stream<Object> emptyStream = Stream.empty();
③ Stream.builder()
使用构建器模式(Builder Pattern)一步步构建流,适用于动态添加元素的场景。
java
Stream<String> builtStream = Stream.<String>builder()
.add("dog")
.add("cat")
.add("bird")
.build();
4. 创建无限流(Infinite Streams)
无限流会源源不断地产生数据,通常需要配合 limit() 方法来截断,否则会无限循环。
① Stream.generate(Supplier<T> s)
接受一个无参的供给型函数,用于生成无限个元素(常用于生成随机数、常量等)。
java
// 生成 5 个随机数并打印
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
② Stream.iterate(T seed, UnaryOperator<T> f)
接受一个种子值(初始值)和迭代器函数,后一个元素基于前一个元素产生(如等差数列)。
java
// 从 0 开始,每次加 2,生成 5 个数:0, 2, 4, 6, 8
Stream.iterate(0, n -> n + 2)
.limit(5)
.forEach(System.out::println);
// Java 9 引入的重载版本,支持加入判断条件(类似于 for 循环)
Stream.iterate(0, n -> n < 10, n -> n + 2)
.forEach(System.out::println);
5. 创建基本折叠类型流(数值流)
为了避免装箱和拆箱的性能开销,Java 提供了三个特化版的数值流:IntStream、LongStream 和 DoubleStream。
它们有自己独有的创建方式:
java
// 1. 包含 1, 2, 3
IntStream intStream = IntStream.of(1, 2, 3);
// 2. range(): 范围 [1, 5) ── 输出 1, 2, 3, 4
IntStream range = IntStream.range(1, 5);
// 3. rangeClosed(): 范围 [1, 5] ── 输出 1, 2, 3, 4, 5
IntStream rangeClosed = IntStream.rangeClosed(1, 5);
6. 通过 I/O 文件操作创建
Java 的 java.nio.file.Files 类提供了许多方法,可以直接将文件内容、目录信息等转换为流。
注意:这类流通常持有底层资源,建议使用 try-with-resources 自动关闭流。
① 按行读取文件 Files.lines()
java
Path path = Paths.get("data.txt");
try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
lines.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
② 获取目录下的文件列表 Files.list()
java
try (Stream<Path> paths = Files.list(Paths.get("."))) {
paths.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
7. 其他 API 转换
许多 Java 常用类也专门提供了支持 Stream 的方法。
① 正则表达式 Pattern.splitAsStream()
将字符串按正则分割并直接转换为流。
java
Pattern pattern = Pattern.compile(",");
Stream<String> stream = pattern.splitAsStream("apple,banana,orange");
② 随机数流 Random.ints()
Random 类提供了生成随机数值流的方法。
java
new Random().ints(5) // 生成 5 个随机整数
.forEach(System.out::println);
总结建议
- 最常用:
Collection.stream()(处理已有集合)和Stream.of()(临时测试)。 - 处理数值:优先使用
IntStream/LongStream/DoubleStream以提升性能。 - 读取文件:优先使用
Files.lines(),性能优于传统逐行读取,且代码极其简洁。