您好,欢迎来到欧得旅游网。
搜索
您的当前位置:首页stream流学习总结(超详细)

stream流学习总结(超详细)

来源:欧得旅游网


前言

在 Java 编程的世界中,数据处理是一个极为重要的环节。

随着 Java 8 的推出,Java Stream 这一强大的特性为开发者们带来了全新的数据处理方式。它像是一把精巧的瑞士军刀,为我们在处理集合等数据时提供了高效、简洁且灵活的解决方案。

无论是对数据进行筛选、转换还是复杂的组合操作,Java Stream 都展现出了独特的优势。

本指南将深入探讨 Java Stream 的方方面面,包括它的概念、创建方式、常用操作方法以及并行流相关的特性和注意事项,帮助读者全面掌握这一实用的编程工具,提升在 Java 数据处理方面的能力。

一. 什么是 Java Stream?

Java Stream 是 Java 8 中引入的一个新的抽象层,它可以让你以一种声明式的方式处理集合(Collection)等数据。它提供了一种高效且易于理解的方式来对数据进行操作,如过滤、映射、排序等。Stream 不是数据结构,它不会存储数据,而是通过管道(pipeline)的方式对数据进行处理。

举个例子:你有一个包含整数的列表,想要获取其中所有大于 10 的偶数,使用传统的方式可能需要写一个循环来遍历列表,然后使用条件判断来筛选出符合要求的元素。而使用 Stream,你可以用更简洁的方式表达这个操作。

Stream 的优势:

代码简洁性:可以用更简洁的方式表达复杂的数据处理逻辑,减少了循环和条件判断的嵌套。

可读性:声明式的编程风格使得代码的意图更加清晰,更容易理解数据的处理流程。

可并行性:方便地利用多核处理器来提高性能,而不需要手动管理线程。

二. Stream 的创建

1. 从集合创建

Java 集合接口ListSetMap等都提供了两个方法:

1. stream()方法来创建一个顺序流

2. parallelStream()方法来创建一个并行流

两者区别:

顺序流和并行流的区别在于它们的处理方式不同,顺序流是单线程的,而并行流是多线程的。使用的方法也有一些区别。例如:

顺序流:

执行方式:

顺序流是按照元素在集合中的顺序依次处理每个元素。在处理过程中,一个元素的操作完成后才会开始下一个元素的操作。

性能:

当处理大规模数据并且操作可以并行化时,顺序流可能会比较慢,因为它只能使用一个线程来处理所有数据。

线程安全和数据一致性:

顺序流由于是单线程进行操作,所以不存在线程安全问题。

并行流:

执行方式:

处理速度:并行流会将数据分成多个部分,同时在多个线程中对这些部分进行处理。它利用了多核处理器的优势,通过并行计算来提高处理速度。

性能:

并行流在处理大规模数据并且操作允许并行执行时,能够显著提高性能。例如,对一个包含大量整数的列表进行求和操作,使用并行流可以利用多核处理器同时计算多个部分的和,然后再合并结果,从而加快计算速度。

线程安全和数据一致性:

并行流在处理过程中会涉及多个线程同时访问数据,因此可能会出现线程安全问题。如果在并行流操作中修改共享数据,可能会导致数据不一致或错误的结果。

创建两种流的代码如下:

import java.util.ArrayList;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        // 创建顺序流
        java.util.stream.Stream<Integer> stream = numbers.stream();
        // 创建并行流
        java.util.stream.Stream<Integer> parallelStream = numbers.parallelStream();
    }
}

2. 从数组创建

可以使用Arrays.stream()方法从数组创建一个流

代码如下:

import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        java.util.stream.Stream<int[]> stream = Arrays.stream(numbers);
    }
}

3. 使用 Stream.of () 方法创建

可以将多个元素作为参数传递给Stream.of()方法来创建一个流。

代码如下:

import java.util.stream.Stream;
public class Main {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("apple", "banana", "cherry");
    }
}

三. 常用操作方法

1. 中间操作

过滤(filter)

用于筛选出符合特定条件的元素。它接受一个Predicate(一个返回boolean值的函数式接口)作为参数。

代码示例:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        Stream<Integer> filteredStream = numbers.stream().filter(n -> n % 2 == 0);
        // 过滤后的流只包含偶数
        filteredStream.forEach(System.out::println);
    }
}

 映射(map)

用于将流中的每个元素按照指定的函数进行转换。它接受一个Function(一个接受一个参数并返回一个结果的函数式接口)作为参数。

代码示例:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        Stream<String> mappedStream = numbers.stream().map(n -> "Number: " + n);
        mappedStream.forEach(System.out::println);
    }
}

去重(distinct

distinct操作会去除流中重复的元素。它是通过比较元素的equals方法来判断元素是否相同

所以要是对对象进行去重操作的话,要想达到去重效果,对象内部必须重写equals等方法。

import java.util.ArrayList;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(1);
        numbers.add(3);
        List<Integer> distinctNumbers = numbers.stream()
              .distinct()
              .collect(Collectors.toList());
        for (Integer number : distinctNumbers) {
            System.out.println(number);
        }
    }
}

排序(sorted)

用于对流中的元素进行排序。如果流中的元素是自定义类,需要实现Comparable接口或者提供一个Comparator

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(3);
        numbers.add(1);
        numbers.add(2);
        Stream<Integer> sortedStream = numbers.stream().sorted();
        sortedStream.forEach(System.out::println);
    }
}

2. 终端操作

遍历(forEach)

用于遍历流中的每个元素,并对每个元素执行给定的操作。它接受一个Consumer(一个接受一个参数但不返回结果的函数式接口)作为参数。

import java.util.ArrayList;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.stream().forEach(System.out::println);
    }
}

收集(collect) 

用于将流中的元素收集到一个集合或者其他数据结构中。它接受一个Collector作为参数。Collectors类提供了许多用于创建收集器的静态方法。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
        System.out.println(evenNumbers);
    }
}

计数(count)

用于返回流中元素的数量

import java.util.ArrayList;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        long count = numbers.stream().filter(n -> n % 2 == 0).count();
        System.out.println(count);
    }
}

四. 并行流(Parallel Streams)

并行流可以利用多核处理器的优势来提高性能。当你调用集合的parallelStream()方法或者对流调用parallel()方法时,就会创建一个并行流。但要考虑数据安全问题。

注意:

并不是所有的操作在并行流中都能获得性能提升。对于一些简单的操作或者数据量较小的情况,并行流可能会因为线程管理等开销而比顺序流更慢。

代码示例:

import java.util.ArrayList;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            numbers.add(i);
        }
        long startTime = System.currentTimeMillis();
        long sumSequential = numbers.stream().reduce(0, (a, b) -> a + b);
        long endTimeSequential = System.currentTimeMillis();
        System.out.println("Sequential sum took: " + (endTimeSequential - startTime) + "ms");
        startTime = System.currentTimeMillis();
        long sumParallel = numbers.parallelStream().reduce(0, (a, b) -> a + b);
        long endTimeParallel = System.currentTimeMillis();
        System.out.println("Parallel sum took: " + (endTimeParallel - startTime) + "ms");
    }
}

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- ovod.cn 版权所有 湘ICP备2023023988号-4

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务