Java Stream 流详解

Java Stream 流详解

JDK 8 中的 Stream 流是一个处理集合数据的新方式。它允许以声明性方式操作数据,支持并行处理,提供了丰富的操作方法如映射、过滤、排序等,可以极大简化集合处理的代码。

Stream 流具有以下特点:

  1. 不是数据结构: 它不存储数据,而是提供了一种流水线操作数据的方法。
  2. 函数式编程风格: 可以通过链式调用操作方法,如 mapfilterreduce 等,更加灵活和简洁。
  3. 惰性求值: 只有在终止操作调用时才会真正执行流水线操作,这样可以避免不必要的计算。
  4. 支持并行处理: 可以轻松地使用并行流进行并行处理,提高处理大数据集合的效率。

Stream 流的使用可以显著简化代码,提高代码的可读性和维护性,是 JDK 8 引入的重要特性之一。

一、常用特点

JDK 8 中 Stream 流的常用特点包括:

  1. 有序性(Order)
    • 流保持其元素的有序性,除非显式地使用无序操作。
    • 比如,从列表生成的流会保持列表的顺序。
  2. 惰性求值(Lazy Evaluation)
    • 中间操作(如 filtermap)是惰性求值的,只有在终止操作(如 collectforEach)调用时才会真正执行。
    • 这样可以优化性能,避免不必要的计算。
  3. 无存储(No Storage)
    • 流本身不存储数据,它从底层的数据结构、数组或 I/O 通道等数据源中获取数据。
    • 数据源可以是集合、数组、I/O 频道等。
  4. 不可变性(Immutability)
    • 流操作不会修改其数据源中的元素,而是生成新的流。
    • 这种不可变性有助于并行处理和线程安全。
  5. 支持并行(Parallelism)
    • 流可以轻松转换为并行流,使用多核处理器加速处理。
    • 通过调用 parallelStream()parallel() 方法。
  6. 支持聚合操作(Aggregation Operations)
    • Stream API 提供了丰富的聚合操作,如 reducecollect 等,可以方便地对数据进行聚合计算。
  7. 支持无限流(Infinite Streams)
    • 流可以是有限的也可以是无限的。无限流可以使用 generateiterate 方法创建。
    • 处理无限流时通常需要使用限制操作如 limit
  8. 可组合(Composable)
    • 流的中间操作可以组合起来形成复杂的数据处理流水线。
    • 通过链式调用实现数据过滤、转换、排序等操作。

二、基本概念与操作

(一)、创建Stream

以下是几种常见的创建 Stream 的方法:

1. 从集合创建 【常用】

可以通过集合(如 List、Set)创建 Stream。

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

public class StreamFromCollection {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b", "c");
        Stream<String> stream = list.stream();
        stream.forEach(System.out::println);
    }
}

2. 从数组创建【常用】

可以通过数组创建 Stream。

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

public class StreamFromArray {
    public static void main(String[] args) {
        String[] array = {"a", "b", "c"};
        Stream<String> stream = Arrays.stream(array);
        stream.forEach(System.out::println);

        // 对于基本类型数组,可以使用特定的流类型
        int[] intArray = {1, 2, 3};
        IntStream intStream = Arrays.stream(intArray);
        intStream.forEach(System.out::println);
    }
}

3. 使用 Stream.of 方法【常用】

可以使用 Stream.of 方法直接创建 Stream。

import java.util.stream.Stream;

public class StreamOf {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("a", "b", "c");
        stream.forEach(System.out::println);

        // 创建空流
        Stream<String> emptyStream = Stream.empty();
        emptyStream.forEach(System.out::println);  // 无输出
    }
}

4. 使用 Stream.generate 方法

可以使用 Stream.generate 方法创建无限流

在Java的流(Stream)API中,你可以使用 Stream.generate() 或者 Stream.iterate() 方法来创建无限流。这些方法允许你提供一个生成元素的函数,并且不受固定大小的限制。例如,可以使用 Stream.generate(Math::random) 来生成一个无限的随机数流,或者使用 Stream.iterate(0, n -> n + 1) 来生成一个从0开始的整数无限流。

处理无限流时需要特别注意,通常需要使用流操作(如 .limit(n))来限制元素数量,否则可能会导致无限循环或内存耗尽的问题。无限流的特性使得它们在某些情况下非常有用,例如在模拟、数学运算或者需要动态生成数据时。

import java.util.stream.Stream;

public class StreamGenerate {
    public static void main(String[] args) {
        Stream<Double> stream = Stream.generate(Math::random).limit(5);
        stream.forEach(System.out::println);
    }
}

5. 使用 Stream.iterate 方法【常用】

可以使用 Stream.iterate 方法生成具有特定规则的无限流。

import java.util.stream.Stream;

public class StreamIterate {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);
        stream.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 StreamFromFile {
    public static void main(String[] args) {
        try (Stream<String> stream = Files.lines(Paths.get("path/to/file.txt"))) {
            stream.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7. 从其他数据源创建

Stream 还可以从其他数据源创建,例如通过 BufferedReaderlines 方法从 I/O 流中创建,或者通过 Pattern.splitAsStream 从正则表达式分割结果中创建。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.regex.Pattern;
import java.util.stream.Stream;

public class StreamFromOtherSources {
    public static void main(String[] args) throws IOException {
        // 从 BufferedReader 创建 Stream
        String text = "Hello\\nWorld\\nStream";
        BufferedReader reader = new BufferedReader(new StringReader(text));
        Stream<String> streamFromReader = reader.lines();
        streamFromReader.forEach(System.out::println);

        // 从正则表达式分割结果创建 Stream
        String textToSplit = "apple,banana,orange";
        Stream<String> streamFromPattern = Pattern.compile(",").splitAsStream(textToSplit);
        streamFromPattern.forEach(System.out::println);
    }
}

除了上述提到的方式,还有一些特定的创建 Stream 的方法和技巧:

8. 使用 Stream.builder 方法

可以使用 Stream.builder 创建一个可变的 Stream。

import java.util.stream.Stream;

public class StreamBuilder {
    public static void main(String[] args) {
        Stream.Builder<String> builder = Stream.builder();
        builder.add("a")
               .add("b")
               .add("c");

        Stream<String> stream = builder.build();
        stream.forEach(System.out::println);
    }
}

9. 使用 Stream.concat 方法

可以使用 Stream.concat 方法将两个 Stream 连接起来。

import java.util.stream.Stream;

public class StreamConcat {
    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("a", "b");
        Stream<String> stream2 = Stream.of("c", "d");

        Stream<String> concatenatedStream = Stream.concat(stream1, stream2);
        concatenatedStream.forEach(System.out::println);
    }
}

10. 使用 Pattern.splitAsStream 方法

可以使用 Pattern.splitAsStream 方法从正则表达式分割结果中创建 Stream。

import java.util.regex.Pattern;
import java.util.stream.Stream;

public class StreamSplitAsStream {
    public static void main(String[] args) {
        String text = "apple,banana,orange";
        Stream<String> stream = Pattern.compile(",").splitAsStream(text);
        stream.forEach(System.out::println);
    }
}

11. 从 Optional 创建

可以使用 Optional.stream 方法从 Optional 对象中创建一个包含零个或一个元素的 Stream。

import java.util.Optional;
import java.util.stream.Stream;

public class StreamFromOptional {
    public static void main(String[] args) {
        Optional<String> optional = Optional.of("value");
        Stream<String> stream = optional.stream();
        stream.forEach(System.out::println);
    }
}

12. 自定义实现 Stream

在某些情况下,可能需要自定义实现 Stream。这通常涉及实现 Spliterator 接口来定义迭代器行为,然后使用 StreamSupport.stream 方法创建 Stream。

import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class CustomStream {
    public static void main(String[] args) {
        // 自定义 Spliterator
        Spliterator<String> spliterator = new Spliterator<String>() {
            private String[] elements = {"a", "b", "c"};
            private int index = 0;

            @Override
            public boolean tryAdvance(Consumer<? super String> action) {
                if (index < elements.length) {
                    action.accept(elements[index++]);
                    return true;
                }
                return false;
            }

            @Override
            public Spliterator<String> trySplit() {
                return null;  // 不支持分割
            }

            @Override
            public long estimateSize() {
                return elements.length - index;
            }

            @Override
            public int characteristics() {
                return ORDERED | SIZED | SUBSIZED;
            }
        };

        // 使用 StreamSupport 创建 Stream
        Stream<String> stream = StreamSupport.stream(spliterator, false);
        stream.forEach(System.out::println);
    }
}

(二)中间操作

1. filter

filter 用于根据指定的条件筛选流中的元素,保留符合条件的元素。

解释:

  • filter 方法接受一个 Predicate 函数式接口,即一个返回 boolean 值的 lambda 表达式或方法引用。
  • 对流中的每个元素应用该谓词,如果返回 true,则该元素会被保留在结果流中,否则会被过滤掉。

示例:

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

public class FilterExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "banana", "orange", "pear");
        List<String> filteredList = list.stream()
                                        .filter(s -> s.startsWith("a"))
                                        .collect(Collectors.toList());
        System.out.println(filteredList);  // 输出: [apple]
    }
}

2. map

map 用于将流中的每个元素转换为另一种类型的元素。

解释:

  • map 方法接受一个 Function 函数式接口,即一个接收一个参数并返回一个结果的 lambda 表达式或方法引用。
  • 对流中的每个元素应用该函数,将其转换为另一种类型的新元素,并将这些新元素组成一个新的流。

示例:

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

public class MapExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "banana", "orange");
        List<Integer> lengths = list.stream()
                                    .map(String::length)
                                    .collect(Collectors.toList());
        System.out.println(lengths);  // 输出: [5, 6, 6]
    }
}

3. flatMap

flatMap 用于将流中的每个元素转换为一个流,然后将这些流合并为一个新的流。

解释:

  • flatMap 方法接受一个 Function 函数式接口,该接口将每个元素转换为一个流。
  • 这些流将被扁平化为一个单一的流。

示例:

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

public class FlatMapExample {
    public static void main(String[] args) {
        List<List<String>> listOfLists = Arrays.asList(
            Arrays.asList("a", "b"),
            Arrays.asList("c", "d"),
            Arrays.asList("e", "f")
        );
        List<String> flatList = listOfLists.stream()
                                           .flatMap(List::stream)
                                           .collect(Collectors.toList());
        System.out.println(flatList);  // 输出: [a, b, c, d, e, f]
    }
}

4. distinct

distinct 用于去除流中的重复元素,只保留唯一的元素。

解释:

  • distinct 方法使用元素的 equals 方法来判断元素是否重复。

示例:

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

public class DistinctExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
        List<Integer> distinctList = list.stream()
                                         .distinct()
                                         .collect(Collectors.toList());
        System.out.println(distinctList);  // 输出: [1, 2, 3, 4, 5]
    }
}

5. sorted

sorted 用于对流中的元素进行排序。

解释:

  • sorted 方法有两个变体,一个不带参数,默认按自然顺序排序;另一个带参数,可以传递一个 Comparator 函数式接口以指定排序规则。

示例:

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

public class SortedExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "orange", "banana", "pear");
        List<String> sortedList = list.stream()
                                      .sorted()
                                      .collect(Collectors.toList());
        System.out.println(sortedList);  // 输出: [apple, banana, orange, pear]

        // 自定义排序
        List<String> reverseSortedList = list.stream()
                                             .sorted((s1, s2) -> s2.compareTo(s1))
                                             .collect(Collectors.toList());
        System.out.println(reverseSortedList);  // 输出: [pear, orange, banana, apple]
    }
}

6. limit

limit 用于截取流中的前 N 个元素。

解释:

  • limit 方法接受一个 long 类型的参数,表示要截取的元素个数。

示例:

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

public class LimitExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> limitedList = list.stream()
                                        .limit(3)
                                        .collect(Collectors.toList());
        System.out.println(limitedList);  // 输出: [1, 2, 3]
    }
}

7. skip

skip 用于跳过流中的前 N 个元素。

解释:

  • skip 方法接受一个 long 类型的参数,表示要跳过的元素个数。

示例:

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

public class SkipExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> skippedList = list.stream()
                                        .skip(2)
                                        .collect(Collectors.toList());
        System.out.println(skippedList);  // 输出: [3, 4, 5]
    }
}

8. peek

peek 用于对流中的每个元素执行操作并返回一个新的流,该操作通常用于调试。

解释:

  • peek 方法接受一个 Consumer 函数式接口,即一个接收一个参数并不返回结果的 lambda 表达式或方法引用。

示例:

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

public class PeekExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "banana", "orange");
        List<String> resultList = list.stream()
                                      .peek(s -> System.out.println("Processing: " + s))
                                      .map(String::toUpperCase)
                                      .collect(Collectors.toList());
        System.out.println(resultList);  // 输出: [APPLE, BANANA, ORANGE]
    }
}

9. takeWhile(Java 9 及以上版本中可用)

takeWhile 按照条件从流中获取元素,直到条件为 false 时停止。

解释:

  • takeWhile 方法接受一个 Predicate 函数式接口,即一个返回 boolean 值的 lambda 表达式或方法引用。
  • 对流中的每个元素应用该谓词,直到遇到返回 false 的元素时停止获取。

示例:

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

public class TakeWhileExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> resultList = list.stream()
                                       .takeWhile(n -> n < 4)
                                       .collect(Collectors.toList());
        System.out.println(resultList);  // 输出: [1, 2, 3]
    }
}

10. dropWhile(Java 9 及以上版本中可用)

dropWhile 按照条件丢弃元素,直到条件为 false 时开始获取剩余的元素。

解释:

  • dropWhile 方法接受一个 Predicate 函数式接口,即一个返回 boolean 值的 lambda 表达式或方法引用。
  • 对流中的每个元素应用该谓词,直到遇到返回 false 的元素时开始获取剩余的元素。

示例:

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

public class DropWhileExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> resultList = list.stream()
                                       .dropWhile(n -> n < 4)
                                       .collect(Collectors.toList());
        System.out.println(resultList);  // 输出: [4, 5, 6]
    }
}

11. flatMapToIntflatMapToDoubleflatMapToLong

这些方法用于将元素转换为对应的基本类型流。

解释:

  • flatMapToIntflatMapToDoubleflatMapToLong 方法分别用于将元素转换为 IntStreamDoubleStreamLongStream
  • 接受一个函数,将元素转换为基本类型的流。

示例:

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

public class FlatMapToIntExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("1", "2", "3");
        IntStream intStream = list.stream()
                                  .flatMapToInt(s -> IntStream.of(Integer.parseInt(s)));
        intStream.forEach(System.out::println);  // 输出: 1 2 3
    }
}

12. mapToIntmapToDoublemapToLong

这些方法用于将元素映射为对应的基本类型流。

解释:

  • mapToIntmapToDoublemapToLong 方法分别用于将元素映射为 IntStreamDoubleStreamLongStream
  • 接受一个函数,将元素转换为对应的基本类型。

示例:

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

public class MapToIntExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("1", "2", "3");
        IntStream intStream = list.stream()
                                  .mapToInt(Integer::parseInt);
        intStream.forEach(System.out::println);  // 输出: 1 2 3
    }
}

(三)、终止操作

下面是一些常见的Stream 流中的终止操作,包括其功能、使用场景和示例代码。

1. forEach

forEach 是用于遍历流中的每一个元素,并对每个元素执行指定的操作。通常用于打印或更新元素。

功能

  • 对流中的每个元素执行一个动作。
  • 该动作通常是一个 Consumer 接口的实现。

使用场景

  • 遍历并打印流中的元素。
  • 对流中的元素执行某种操作,如更新状态。

示例代码

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

public class ForEachExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "def", "ghi");

        // 使用 forEach 打印每个元素
        strings.stream()
               .forEach(System.out::println);
    }
}

2. collect

collect 是用于将流中的元素收集到一个结果容器中,如 List、Set 或 Map。它是流中最灵活和最强大的终止操作之一。

功能

  • 将流中的元素聚集到一个容器中(如 ListSetMap)。
  • 使用 Collector 进行收集操作,Collectors 工具类提供了大量预定义的收集器。

使用场景

  • 将流转换为其他数据结构(如 List、Set)。
  • 对流中的数据进行分组、分区等复杂操作。

示例代码

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

public class CollectExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");

        // 过滤空字符串并收集结果到 List
        List<String> filteredList = strings.stream()
                                           .filter(string -> !string.isEmpty())
                                           .collect(Collectors.toList());

        // 将字符串收集到 Set 中
        Set<String> stringSet = strings.stream()
                                       .filter(string -> !string.isEmpty())
                                       .collect(Collectors.toSet());

        System.out.println("Filtered List: " + filteredList);
        System.out.println("Set: " + stringSet);
    }
}

3. reduce

reduce 是用于将流中的元素组合成一个单一的值。常见的使用场景包括求和、计算乘积、连接字符串等。

功能

  • 将流中的元素通过累加器函数组合成一个值。
  • 可以有一个初始值,或者返回一个 Optional 值。

使用场景

  • 累加、乘积等聚合操作。
  • 将流中的元素按某种规则合并。

示例代码

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

public class ReduceExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 计算所有数的和
        int sum = numbers.stream()
                         .reduce(0, Integer::sum);

        // 计算所有数的乘积
        Optional<Integer> product = numbers.stream()
                                           .reduce((a, b) -> a * b);

        System.out.println("Sum: " + sum);
        product.ifPresent(result -> System.out.println("Product: " + result));
    }
}

4. count

count 是用于计算流中元素的个数,返回一个 long 类型的值。

功能

  • 计算流中元素的数量。

使用场景

  • 统计流中元素的个数。

示例代码

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

public class CountExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");

        // 计算非空字符串的个数
        long count = strings.stream()
                            .filter(string -> !string.isEmpty())
                            .count();

        System.out.println("Count: " + count);
    }
}

5. anyMatchallMatchnoneMatch

这些方法用于判断流中的元素是否满足指定的条件,返回值是 boolean 类型。

功能

  • anyMatch:流中是否有任意一个元素满足条件。
  • allMatch:流中是否所有元素都满足条件。
  • noneMatch:流中是否所有元素都不满足条件。

使用场景

  • 用于验证流中元素是否符合特定条件。

示例代码

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

public class MatchExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "def", "ghi");

        // 是否存在以 "a" 开头的字符串
        boolean anyStartsWithA = strings.stream()
                                        .anyMatch(s -> s.startsWith("a"));

        // 是否所有字符串长度都大于 2
        boolean allLengthGreaterThan2 = strings.stream()
                                               .allMatch(s -> s.length() > 2);

        // 是否所有字符串都不为空
        boolean noneEmpty = strings.stream()
                                   .noneMatch(String::isEmpty);

        System.out.println("Any starts with 'a': " + anyStartsWithA);
        System.out.println("All length greater than 2: " + allLengthGreaterThan2);
        System.out.println("None empty: " + noneEmpty);
    }
}

6. findFirstfindAny

这两个方法用于从流中查找元素,返回一个 Optional 对象。

功能

  • findFirst:返回流中的第一个元素,适用于有序流。
  • findAny:返回流中的任意一个元素,适用于并行流。

使用场景

  • 查找流中的某个元素。

示例代码

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

public class FindExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "def", "ghi");

        // 查找第一个元素
        Optional<String> first = strings.stream()
                                        .findFirst();

        // 查找任意一个元素
        Optional<String> any = strings.stream()
                                      .findAny();

        first.ifPresent(s -> System.out.println("First: " + s));
        any.ifPresent(s -> System.out.println("Any: " + s));
    }
}

以下是一些额外的终止操作及其详细说明和示例代码:

7. toArray

toArray 是用于将流中的元素收集到一个数组中。

功能

  • 将流中的元素转换为一个数组。

使用场景

  • 当需要将流转换为数组进行进一步处理时使用。

示例代码

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

public class ToArrayExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "def", "ghi");

        // 将流转换为数组
        String[] stringArray = strings.stream()
                                      .toArray(String[]::new);

        System.out.println("Array: " + Arrays.toString(stringArray));
    }
}

8. minmax

minmax 是用于根据给定的比较器找出流中的最小值和最大值,返回一个 Optional 对象。

功能

  • min:找出流中的最小值。
  • max:找出流中的最大值。

使用场景

  • 当需要找到集合中的最小或最大元素时使用。

示例代码

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

public class MinMaxExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(3, 5, 1, 2, 4);

        // 找出最小值
        Optional<Integer> min = numbers.stream()
                                       .min(Comparator.naturalOrder());

        // 找出最大值
        Optional<Integer> max = numbers.stream()
                                       .max(Comparator.naturalOrder());

        min.ifPresent(value -> System.out.println("Min: " + value));
        max.ifPresent(value -> System.out.println("Max: " + value));
    }
}

9. summaryStatistics

summaryStatistics 是用于获取流中元素的统计信息,如计数、总和、最小值、最大值和平均值。该操作通常用于数值流。

功能

  • 获取流中元素的统计信息。

使用场景

  • 当需要一次性获取流中的各种统计数据时使用。

示例代码

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

public class SummaryStatisticsExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(3, 5, 1, 2, 4);

        // 获取统计信息
        IntSummaryStatistics stats = numbers.stream()
                                            .mapToInt(Integer::intValue)
                                            .summaryStatistics();

        System.out.println("Count: " + stats.getCount());
        System.out.println("Sum: " + stats.getSum());
        System.out.println("Min: " + stats.getMin());
        System.out.println("Max: " + stats.getMax());
        System.out.println("Average: " + stats.getAverage());
    }
}

10. joining

joining 是一个特殊的收集器,它将流中的字符串连接成一个字符串。可以指定分隔符、前缀和后缀。

功能

  • 将流中的字符串连接成一个字符串。

使用场景

  • 当需要将多个字符串连接成一个时使用。

示例代码

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

public class JoiningExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("abc", "def", "ghi");

        // 将字符串连接成一个字符串,使用逗号分隔
        String result = strings.stream()
                               .collect(Collectors.joining(", "));

        System.out.println("Joined String: " + result);
    }
}

11. groupingBy

groupingBy 是一个特殊的收集器,用于将流中的元素按指定的分类函数进行分组,返回一个 Map,其中键是分类函数的结果,值是属于该分类的元素列表。

功能

  • 将流中的元素按分类函数进行分组。

使用场景

  • 当需要按某个标准对流中的元素进行分组时使用。

示例代码

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

public class GroupingByExample {
    public static void main(String[] args) {
        List<String> strings = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");

        // 按字符串长度分组
        Map<Integer, List<String>> groupedByLength = strings.stream()
                                                            .collect(Collectors.groupingBy(String::length));

        System.out.println("Grouped by Length: " + groupedByLength);
    }
}

12. partitioningBy

partitioningBy 是一个特殊的收集器,用于将流中的元素按指定的谓词(返回 boolean 的函数)进行分区,返回一个 Map,其中键是 boolean 值,值是属于该分区的元素列表。

功能

  • 将流中的元素按谓词进行分区。

使用场景

  • 当需要按某个条件将流中的元素分成两组时使用。

示例代码

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

public class PartitioningByExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);

        // 按是否为偶数分区
        Map<Boolean, List<Integer>> partitionedByEven = numbers.stream()
                                                               .collect(Collectors.partitioningBy(n -> n % 2 == 0));

        System.out.println("Partitioned by Even: " + partitionedByEven);
    }
}

以上是一些其他常见的 Stream 流终止操作。通过这些操作,可以实现对流中数据的各种处理和转换,生成需要的结果。

  • 29
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值