专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java 8 Stream API 详解(java.stream)

temp10 2025-06-23 21:50:28 java教程 4 ℃ 0 评论


Java 8 Stream API 详解

一、概述

在 Java 8 中,Stream API 是一个重要的新特性。它为处理集合(如 List、Set 等)中的元素提供了一种高效且富有表现力的方式。Stream API 允许开发者以声明式的方式处理数据,将数据处理逻辑与数据存储结构分离,使得代码更加简洁、易读和可维护。同时,Stream API 支持并行处理,能够充分利用多核处理器的性能。

Java 8 Stream API 详解(java.stream)

二、Stream 的概念

2.1 什么是 Stream

Stream 不是一种数据结构,它是对数据源(如集合、数组等)的元素进行一系列操作的抽象。可以将 Stream 看作是一个高级迭代器,它允许我们以一种更灵活的方式遍历和处理集合中的元素。

2.2 Stream 的特点

  • 不存储数据:Stream 只是对数据源中的元素进行操作,不存储元素本身。
  • 函数式编程:使用 Lambda 表达式来定义操作,代码简洁且易于理解。
  • 延迟执行:Stream 的中间操作不会立即执行,只有在调用终止操作时才会触发执行。
  • 可并行操作:Stream 可以并行处理元素,提高处理效率。

三、创建 Stream

3.1 从集合创建 Stream

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamCreationFromCollection {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("banana");
        fruits.add("cherry");

        // 创建顺序流
        Stream<String> sequentialStream = fruits.stream();

        // 创建并行流
        Stream<String> parallelStream = fruits.parallelStream();
    }
}

3.2 从数组创建 Stream

import java.util.stream.Stream;

public class StreamCreationFromArray {
    public static void main(String[] args) {
        String[] colors = {"red", "green", "blue"};
        Stream<String> colorStream = Stream.of(colors);
    }
}

3.3 使用 Stream.generate() 和 Stream.iterate() 创建无限流

import java.util.stream.Stream;

public class InfiniteStreamCreation {
    public static void main(String[] args) {
        // 使用 generate 创建无限流,生成随机数
        Stream<Double> randomStream = Stream.generate(Math::random);
        randomStream.limit(5).forEach(System.out::println);

        // 使用 iterate 创建无限流,从 0 开始,每次递增 2
        Stream<Integer> evenStream = Stream.iterate(0, n -> n + 2);
        evenStream.limit(5).forEach(System.out::println);
    }
}

四、Stream 的操作

4.1 中间操作

中间操作会返回一个新的 Stream,并且不会立即执行,常见的中间操作有:

4.1.1 过滤(filter)

import java.util.Arrays;
import java.util.List;

public class FilterOperation {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        numbers.stream()
              .filter(n -> n % 2 == 0)
              .forEach(System.out::println);
    }
}

4.1.2 映射(map)

import java.util.Arrays;
import java.util.List;

public class MapOperation {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("hello", "world");
        words.stream()
              .map(String::toUpperCase)
              .forEach(System.out::println);
    }
}

4.1.3 扁平化映射(flatMap)

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class FlatMapOperation {
    public static void main(String[] args) {
        List<List<Integer>> nestedList = Arrays.asList(
                Arrays.asList(1, 2),
                Arrays.asList(3, 4),
                Arrays.asList(5, 6)
        );
        Stream<Integer> flatStream = nestedList.stream()
              .flatMap(List::stream);
        flatStream.forEach(System.out::println);
    }
}

4.1.4 排序(sorted)

import java.util.Arrays;
import java.util.List;

public class SortedOperation {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9);
        numbers.stream()
              .sorted()
              .forEach(System.out::println);

        // 自定义排序
        numbers.stream()
              .sorted((a, b) -> b - a)
              .forEach(System.out::println);
    }
}

4.1.5 去重(distinct)

import java.util.Arrays;
import java.util.List;

public class DistinctOperation {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3);
        numbers.stream()
              .distinct()
              .forEach(System.out::println);
    }
}

4.1.6 截断(limit)和跳过(skip)

import java.util.Arrays;
import java.util.List;

public class LimitAndSkipOperation {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        // 取前 3 个元素
        numbers.stream()
              .limit(3)
              .forEach(System.out::println);

        // 跳过前 2 个元素
        numbers.stream()
              .skip(2)
              .forEach(System.out::println);
    }
}

4.2 终止操作

终止操作会触发中间操作的执行,并产生一个最终结果,常见的终止操作有:

4.2.1 遍历(forEach)

import java.util.Arrays;
import java.util.List;

public class ForEachOperation {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        names.stream()
              .forEach(System.out::println);
    }
}

4.2.2 收集(collect)

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class CollectOperation {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Charlie", 25)
        );

        // 收集到 List
        List<String> names = people.stream()
              .map(Person::getName)
              .collect(Collectors.toList());

        // 按年龄分组
        Map<Integer, List<Person>> groupedByAge = people.stream()
              .collect(Collectors.groupingBy(Person::getAge));

        // 拼接名字
        String namesJoined = people.stream()
              .map(Person::getName)
              .collect(Collectors.joining(", "));
    }
}

4.2.3 统计(count)

import java.util.Arrays;
import java.util.List;

public class CountOperation {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        long count = names.stream()
              .count();
        System.out.println("Number of names: " + count);
    }
}

4.2.4 查找(findFirst、findAny)

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class FindOperation {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        Optional<Integer> firstEven = numbers.stream()
              .filter(n -> n % 2 == 0)
              .findFirst();
        if (firstEven.isPresent()) {
            System.out.println("First even number: " + firstEven.get());
        }

        Optional<Integer> anyEven = numbers.parallelStream()
              .filter(n -> n % 2 == 0)
              .findAny();
        if (anyEven.isPresent()) {
            System.out.println("Any even number: " + anyEven.get());
        }
    }
}

4.2.5 匹配(allMatch、anyMatch、noneMatch)

import java.util.Arrays;
import java.util.List;

public class MatchOperation {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(2, 4, 6, 8);
        boolean allEven = numbers.stream()
              .allMatch(n -> n % 2 == 0);
        System.out.println("All numbers are even: " + allEven);

        boolean anyGreaterThanFive = numbers.stream()
              .anyMatch(n -> n > 5);
        System.out.println("Any number is greater than 5: " + anyGreaterThanFive);

        boolean noneGreaterThanTen = numbers.stream()
              .noneMatch(n -> n > 10);
        System.out.println("None of the numbers is greater than 10: " + noneGreaterThanTen);
    }
}

4.2.6 归约(reduce)

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class ReduceOperation {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        // 无初始值的归约
        Optional<Integer> sumWithoutInitial = numbers.stream()
              .reduce((a, b) -> a + b);
        if (sumWithoutInitial.isPresent()) {
            System.out.println("Sum without initial value: " + sumWithoutInitial.get());
        }

        // 有初始值的归约
        int sumWithInitial = numbers.stream()
              .reduce(10, (a, b) -> a + b);
        System.out.println("Sum with initial value: " + sumWithInitial);
    }
}

五、并行流

并行流可以利用多核处理器并行处理元素,提高处理效率。但并行流并不适用于所有场景,使用时需要注意线程安全和性能开销。

import java.util.Arrays;
import java.util.List;

public class ParallelStreamExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        numbers.parallelStream()
              .map(n -> n * 2)
              .forEach(System.out::println);
    }
}

六、Stream 的使用场景和注意事项

6.1 使用场景

  • 数据过滤和筛选:当需要从大量数据中筛选出符合条件的元素时,Stream 的 filter 操作非常方便。
  • 数据转换:使用 map 和 flatMap 操作可以将数据从一种类型转换为另一种类型。
  • 数据分组和聚合:collect 操作可以实现数据的分组和聚合,如按条件分组、求和、计数等。

6.2 注意事项

  • 流的一次性使用:Stream 只能被使用一次,一旦调用了终止操作,流就会被关闭,再次使用会抛出 IllegalStateException。
  • 并行流的使用:并行流虽然可以提高处理效率,但在数据量较小或操作本身线程安全开销较大时,并行流可能会降低性能。在使用并行流前,需要对数据量和操作复杂度进行评估。

七、总结

Java 8 的 Stream API 为集合数据处理提供了一种强大而灵活的方式。通过声明式的编程风格和丰富的操作方法,开发者可以更高效地处理集合元素,编写更加简洁、易读和可维护的代码。同时,并行流的支持使得在多核处理器上可以充分发挥性能优势。但在使用 Stream API 时,需要注意流的一次性使用和并行流的适用场景。

你觉得这篇关于 Java 8 Stream API 的文章如何?如果你对文章还有其他的想法,比如增加某些 API 的详细使用案例、修改内容侧重点等,都可以随时告诉我。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表