Java中的Stream流

Stream流是Java 8引入的一种对集合数据进行操作的工具,它使得我们能够以声明式的方式处理数据流。Stream API主要用于对集合(如ListSetMap等)进行复杂的操作,如过滤、映射、归约等,而不需要显式地编写循环和条件判断。它采用了一种函数式编程风格,可以让代码更加简洁和易于维护。

1. Stream流的核心概念

Stream API的主要特点包括以下几点:

  • 顺序和并行执行:Stream可以以顺序流或并行流的方式执行操作。顺序流按照顺序处理数据,而并行流可以利用多核处理器并发处理数据,提高性能。

  • 惰性求值:Stream的中间操作是惰性求值的,即这些操作不会立即执行,只有在执行终端操作时才会触发对数据流的实际处理。

  • 不可变性:Stream本身是不可变的,每次对Stream进行操作都会返回一个新的Stream对象,而不会修改原始的数据源。

2. Stream流的操作类型

Stream流的操作分为两种类型:中间操作和终端操作。

2.1 中间操作 (Intermediate Operations)

中间操作是对流中的元素进行转换或过滤的操作,这些操作总是返回一个新的Stream,因此可以链式调用。常见的中间操作包括:

  • filter(Predicate<? super T> predicate): 对流中的元素进行过滤,只保留满足条件的元素。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    Stream<Integer> evenNumbers = numbers.stream()
                                          .filter(n -> n % 2 == 0);
    
  • map(Function<? super T, ? extends R> mapper): 将流中的每个元素映射到另一个元素,通常用于数据转换。

    List<String> strings = Arrays.asList("a", "b", "c");
    Stream<String> upperCaseStrings = strings.stream()
                                             .map(String::toUpperCase);
    
  • flatMap(Function<? super T, ? extends Stream<? extends R>> mapper): 将每个元素映射为一个流,并将这些流合并为一个流。常用于处理嵌套的集合结构。

    List<List<String>> listOfLists = Arrays.asList(
        Arrays.asList("a", "b"), Arrays.asList("c", "d"));
    Stream<String> flatStream = listOfLists.stream()
                                           .flatMap(Collection::stream);
    
  • distinct(): 去除流中重复的元素。

    List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
    Stream<Integer> distinctNumbers = numbers.stream().distinct();
    
  • sorted(): 对流中的元素进行排序,默认使用自然排序,也可以传入自定义的比较器。

    List<Integer> numbers = Arrays.asList(3, 5, 1, 2, 4);
    Stream<Integer> sortedNumbers = numbers.stream().sorted();
    
  • limit(long maxSize): 截取流中前maxSize个元素。

    Stream<Integer> limitedNumbers = numbers.stream().limit(3);
    
  • skip(long n): 跳过流中的前n个元素。

    Stream<Integer> skippedNumbers = numbers.stream().skip(2);
2.2 终端操作 (Terminal Operations)

终端操作会触发流的处理,并生成最终的结果。常见的终端操作包括:

  • forEach(Consumer<? super T> action): 对流中的每个元素执行给定的操作(消费元素)。

    numbers.stream().forEach(System.out::println);
    
  • collect(Collector<? super T, A, R> collector): 将流中的元素收集到某种集合或结果中(如ListSetMap等)。

    List<String> resultList = strings.stream()
                                     .map(String::toUpperCase)
                                     .collect(Collectors.toList());
    
  • toArray(): 将流中的元素收集到一个数组中。

    String[] stringArray = strings.stream().toArray(String[]::new);
    
  • reduce(BinaryOperator<T> accumulator): 将流中的元素通过累积函数合并为一个结果,通常用于求和、乘积等操作。

    int sum = numbers.stream().reduce(0, Integer::sum);
    
  • count(): 返回流中的元素数量。

    long count = numbers.stream().count();
    
  • anyMatch(Predicate<? super T> predicate): 检查是否有任意一个元素满足给定的条件。

    boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);
    
  • allMatch(Predicate<? super T> predicate): 检查是否所有元素都满足给定的条件。

    boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
    
  • noneMatch(Predicate<? super T> predicate): 检查是否没有元素满足给定的条件。

    boolean noneEven = numbers.stream().noneMatch(n -> n % 2 == 0);
    
  • findFirst(): 返回流中的第一个元素的Optional

    Optional<Integer> firstNumber = numbers.stream().findFirst();
    
  • findAny(): 返回流中的任意一个元素的Optional,通常在并行流中使用。

    Optional<Integer> anyNumber = numbers.stream().findAny();
    

3. Stream的创建方式

Stream流可以通过多种方式创建,常见的创建方式包括:

  • 从集合创建

    List<String> list = Arrays.asList("a", "b", "c");
    Stream<String> stream = list.stream();
    
  • 从数组创建

    String[] array = {"a", "b", "c"};
    Stream<String> stream = Arrays.stream(array);
    
  • 使用Stream.of方法

    Stream<String> stream = Stream.of("a", "b", "c");
    
  • 从文件创建

    try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
        lines.forEach(System.out::println);
    } catch (IOException e) {
        e.printStackTrace();
    }
    
  • 生成流

    Stream<Integer> evenNumbers = Stream.iterate(0, n -> n + 2).limit(10);
    
  • 并行流:并行流可以并发处理流中的数据。

    Stream<String> parallelStream = list.parallelStream();
    

4. Stream流的并行化

Stream API支持并行化处理,即可以利用多核处理器并发处理数据流,从而提升性能。要使用并行流,只需要调用parallelStream()parallel()方法。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.parallelStream()
       .forEach(n -> System.out.println(n + " " + Thread.currentThread().getName()));

并行流适用于计算密集型任务或处理大规模数据集,但需要注意线程安全问题和性能的合理性。

5. Stream流的应用场景

  • 数据过滤和转换:可以轻松地对数据进行过滤、映射和转换操作。

    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    List<String> upperCaseNames = names.stream()
                                       .filter(name -> name.startsWith("A"))
                                       .map(String::toUpperCase)
                                       .collect(Collectors.toList());
    
  • 聚合和统计:可以对数据进行聚合和统计操作。

    int sum = numbers.stream().reduce(0, Integer::sum);
    long count = numbers.stream().count();
    
  • 并行处理:通过并行流可以利用多核处理器提高处理效率。

    numbers.parallelStream().forEach(System.out::println);
    
  • 处理复杂数据管道:通过链式调用多个Stream操作,可以构建复杂的数据处理管道。

    List<String> result = list.stream()
                              .filter(s -> s.length() > 1)
                              .sorted()
                              .map(String::toUpperCase)
                              .collect(Collectors.toList());
    

总结

Stream API是Java 8引入的一项强大的工具

JavaStreamJava8引入的一个新特性,用于处理集合和数组等数据源的元素。它是一种函数式编程风格的API,可以通过链式调用一系列的操作来实现对数据源的处理,包括过滤、映射、排序、聚合等操作。 Stream分为间操作和终止操作两种类型。间操作是指对数据源进行的转换操作,每次间操作都会返回一个新的Stream对象,可以链式调用多个间操作。终止操作是指对数据源进行的最终操作,会返回一个非Stream类型的结果,例如forEach、count、collect等。 以下是一个简单的示例,演示如何使用Stream对一个整数列表进行过滤、映射和统计操作: ```java 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()); // 将偶数加倍 List<Integer> doubledNumbers = evenNumbers.stream() .map(n -> n * 2) .collect(Collectors.toList()); // 统计偶数的个数 long count = evenNumbers.stream().count(); ``` 在上面的示例,我们首先创建了一个整数列表numbers,然后使用stream()方法将其转换为一个Stream对象。接着使用filter()方法过滤出偶数,并使用collect()方法将结果转换为一个List对象。然后使用map()方法将偶数加倍,并再次使用collect()方法将结果转换为一个List对象。最后使用count()方法统计偶数的个数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值