Java 8新特性Stream()流

简介

Java 8 引入的 Stream API 是 Java 平台的一个重大改进,它提供了一种高效且表达力强的方式来处理数据集合(如 List、Set)。Stream API 可以让你以声明方式处理数据集合(专注于你要做什么,而不是怎么做),并且可以利用多核处理器的优势进行并行计算。Stream API 是 Java 8 引入的一个功能强大的工具,它提供了一种简洁而高效的方式来处理集合数据。通过使用 Stream,我们可以对集合进行过滤、映射、排序、聚合等操作,而无需编写繁琐的循环和条件语句。Stream 的操作可以串行执行,也可以并行执行,从而提高处理大量数据的效率。

主要特性和优点

  1. 函数式编程支持:Stream API 充分利用了 Java 8 的 Lambda 表达式和函数式编程概念。
  2. 声明式数据处理:通过 Stream API,你可以以接近自然语言的方式表达数据处理逻辑,代码更加清晰、简洁。
  3. 并行处理能力:Stream API 提供了自动的并行处理能力,可以简化并行编程的复杂性,可以自动利用多核处理器,提高处理大量数据的效率。
  4. 延迟执行:Stream API 的操作是延迟执行的,这意味着它们不会立即执行,而是等到需要结果时才执行。
  5. 无副作用:Stream API 的操作应该是无副作用的,即它们不会修改数据源。
  6. 易于集成和扩展:Stream API 可以与 Java 集合框架无缝集成,并且可以很容易地通过自定义的 Spliterator 进行扩展。

基本操作

Stream API 中的操作分为两类:中间操作(Intermediate Operations)和终端操作(Terminal Operations)。

1、中间操作:返回 Stream 本身,因此可以链式调用。中间操作是“惰性”的,即在调用终端操作之前,它们不会执行任何处理。常见的中间操作包括 filter(), map(), sorted(), limit(), skip() 等。

中间操作包括有状态和无状态操作两种:

  • 有状态操作:操作需要维护状态来正确执行,每个元素的处理可能依赖于其他元素的状态或上下文。
    例如,sorted和distinct操作,是需要维护一个状态,一个是记录位置,一个是记录是否出现过。

  • 无状态操作:每个元素的处理都是独立的,不依赖于其他元素的状态。
    例如,filter、map和flatMap,只是根据输入元素生成输出元素,而不会受到其他元素的影响。

操作类型 操作方法 描述
中间操作 filter(Predicate<? super T> predicate) 过滤流中的元素,只保留满足谓词条件的元素
map(Function<? super T, ? extends R> mapper) 将流中的每个元素映射成另一种形式
flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) 将流中的每个元素都转换成另一个流,然后将所有流连接成一个流
distinct() 去除流中的重复元素(基于元素的 equals()hashCode() 方法)
sorted() 对流中的元素进行自然排序(需要元素实现了 Comparable 接口)
sorted(Comparator<? super T> comparator) 使用自定义的比较器对流中的元素进行排序
peek(Consumer<? super T> action) 对流中的每个元素执行操作,但不影响流本身,主要用于调试
limit(long maxSize) 限制流的元素个数
skip(long n) 跳过流的前n个元素

2、终端操作:返回一个结果或副作用,例如执行一个操作或返回一个非 Stream 的值。终端操作会触发 Stream 管道中所有中间操作的执行。常见的终端操作包括 forEach(), collect(), reduce(), findFirst(), min(), max() 等。

终止操作包括短路操作和非短路操作两种:

  • 短路操作:处理元素时,满足某个条件就立即返回结果,无需处理所有元素。
    例如,findFirst、findAny、anyMatch和allMatch
  • 非短路操作:指必须处理所有元素才能得到最终结果;
    例如,forEach、reduce和collect
操作类型 操作方法 描述
终止操作 forEach(Consumer<? super T> action) 遍历流中的每个元素并执行操作
toArray() 将流中的元素收集到一个数组中(注意:这通常需要一个显式的类型参数,如 toArray(String[]::new)
reduce(BinaryOperator<T> accumulator) 归约操作,将流中的元素组合起来,得到一个值(需要元素之间有明确的组合方式)
reduce(T identity, BinaryOperator<T> accumulator) 带初始值的归约操作
collect(Collector<? super T, A, R> collector) 收集操作,将流中的元素收集到一个集合中,通常与 Collectors 类一起使用
min(Comparator<? super T> comparator) 找出流中的最小元素(根据提供的比较器)
max(Comparator<? super T> comparator) 找出流中的最大元素(根据提供的比较器)
count() 计算流中元素的个数
anyMatch(Predicate<? super T> predicate) 检查流中是否存在至少一个元素满足条件
allMatch(Predicate<? super T> predicate) 检查流中的所有元素是否都满足条件
noneMatch(Predicate<? super T> predicate) 检查流中是否不存在任何元素满足条件
findFirst() 查找流中的第一个元素(返回一个包含单个元素的 Optional
findAny() 查找流中的任意一个元素(在并行流中可能不返回第一个元素)

官网: Stream()官网

一、操作

1、获取流
1.1 从集合(Collection)中获取
	@Test
    void list() {
   
   
        // 创建一个List集合
        List<String> names = Arrays.asList("John", "Alice", "Bob", "David");

        // 获取顺序流
        Stream<String> stream = names.stream();

        // 使用流进行操作(这里只是示例,没有实际的操作)
         stream.forEach(System.out::println);

        // 获取并行流
        Stream<String> parallelStream = names.parallelStream();

        // 使用并行流进行操作(这里只是示例,没有实际的操作)
        parallelStream.forEach(System.out::println);

        Set<Integer> set = new HashSet<Integer>() {
   
   {
   
   
            add(1);
            add(2);
            add(3);
        }};
        // 通过Set获取
        Stream<Integer> stream2 = set.stream();
        stream2.forEach(System.out::println);
        Map<String, String> map = new HashMap<>();
        map.put("map1","test1");
        map.put("map2","test2");
        // 通过Map.entrySet获取
        Stream<Map.Entry<String, String>> stream3 = map.entrySet().stream();
        stream3.forEach(System.out::println);
        // 通过Map.keySet获取
        Stream<String> stream4 = map.keySet().stream();
        stream4.forEach(System.out::println);
        // 通过Map.values获取
        Stream<String> stream5 = map.values().stream();
        stream5.forEach(System.out::println);
    }
1.2 从数组中获取
	@Test
    void array(){
   
   
        // 对象数组
        String[] strings = {
   
   "Hello", "World", "Java", "Stream"};
        Stream<String> stringStream = Arrays.stream(strings);

        // 基本类型数组(以int为例)
        int[] numbers = {
   
   1, 2, 3, 4, 5};
        Stream<Integer> intStream = Arrays.stream(numbers).boxed(); // 基本类型流需要装箱

        // 使用流进行操作(这里只是示例,没有实际的操作)
         stringStream.forEach(System.out::println);
         intStream.forEach(System.out::println);
    }
1.3 从其他数据源获取流
    @Test
    void stream(){
   
   
        // 使用Stream.of()从多个元素中创建流
        Stream<String> stringStream = Stream.of("Apple", "Banana", "Cherry");

        // 使用Stream.iterate()创建无限流(这里需要提供一个终止条件来限制流的大小)
        Stream<Integer> infiniteIntStream = Stream.iterate(1, n -> n + 1).limit(5); // 生成1到5的流

        // 使用Stream.generate()创建无限流(基于提供的Supplier)
        Stream<Double> randomStream = Stream.generate(Math::random).limit(10); // 生成10个随机数
        
         stringStream.forEach(System.out::println);
         infiniteIntStream.forEach(System.out::println);
         randomStream.forEach(System.out::println);
    }
1.4 从文件中创建流
    @Test
    void file(){
   
   
        // Paths.get("example.txt") 为当前工作目录下名为 example.txt 的文件,没有创建会报错,也可以写绝对路径
        try (Stream<String
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值