跳转到内容

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()`)

graph LR A[创建流] --> B[中间操作] B --> C[中间操作] C --> D[终端操作]

实际应用案例[编辑 | 编辑源代码]

假设我们需要从一个员工列表中找出所有工资高于平均工资的 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 的第一步。后续可以结合各种中间操作和终端操作,构建强大的数据处理流水线。对于初学者,建议从简单的集合流开始练习,逐步掌握更复杂的创建方式。