java Stream流常用操作

1. 简介

1.1 Stream流的概念

在Java 8中,Stream流是一种新的数据处理方式。Stream流并不是数据结构,它不会改变源数据,你可以视为遍历数据的高级迭代器。此外,Stream流可以透明地并行处理,无需我们在代码中手动进行并行处理。

Stream流的操作可以分为两种:中间操作和终止操作。中间操作只对数据做标记,只有在遇到终止操作时才会进行实际的计算。

List<String> list = Arrays.asList("a", "b", "c");
list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);

在上面的代码中,filter是一个中间操作,forEach是一个终止操作。

1.2 为什么需要使用Stream流

在Java 8之前,我们通常使用for循环或者迭代器对集合进行操作。然而,这种方式需要我们显式地在集合上进行迭代,这不仅代码冗长,而且在处理复杂的数据转换和过滤时,代码的可读性和维护性都会下降。

而Stream流提供了一种更高级、更方便的处理方式。它允许我们以声明性的方式处理数据,我们只需要告诉计算机我们想要的结果是什么,而不需要告诉它具体的实现步骤。这使得我们的代码更简洁,更易于阅读和维护。

此外,Stream流的另一个重要特性是它可以透明地进行并行处理。这意味着我们可以充分利用多核处理器的优势,而无需在代码中手动进行多线程管理。

总的来说,使用Stream流可以让我们的代码更简洁,更易于阅读和维护,同时能提高程序的性能。

2. Stream流的创建

在Java 8中,我们可以通过多种方式创建Stream流。以下是一些常见的方法:

2.1 从集合创建Stream

每个Java集合都可以通过stream方法转换为Stream流。

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();

2.2 从数组创建Stream

我们可以使用Arrays.stream方法从数组创建Stream流。

int[] array = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(array);

2.3 使用Stream.of方法创建Stream

Stream.of方法可以接受任意数量的参数,并返回一个Stream流。

Stream<String> stream = Stream.of("a", "b", "c");

2.4 使用IntStream, LongStream, DoubleStream创建Stream

Java 8引入了几种特殊的Stream流,用于处理基本数据类型的值,如IntStreamLongStreamDoubleStream。这些特殊的Stream流提供了一些额外的方法,如sumaverage等。

IntStream stream = IntStream.range(1, 5);

以上就是在Java 8中创建Stream流的一些常见方法。

3. Stream流的常用操作

在Java 8中,Stream流提供了一系列的操作,可以帮助我们更方便地处理数据。以下是一些常用的操作:

3.1 filter操作

filter操作用于过滤Stream流中的元素。它接受一个Predicate接口类型的参数,只有满足该条件的元素才能获取。

List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);

3.2 map操作

map操作用于转换Stream流中的元素。它接受一个Function接口类型的参数,通过这个函数,我们可以将元素转换成其他类型。

List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().map(String::toUpperCase).forEach(System.out::println);

3.3 flatMap操作

flatMap操作用于将Stream流中的每个元素转换成另一个Stream流,然后将所有的Stream流连接成一个Stream流。

List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().flatMap(s -> Stream.of(s.toUpperCase(), s.toLowerCase())).forEach(System.out::println);

3.4 distinct操作

distinct操作用于去除Stream流中的重复元素。

List<String> list = Arrays.asList("a", "b", "c", "a", "b");
list.stream().distinct().forEach(System.out::println);

3.5 limit操作

limit操作用于获取Stream流中的前n个元素。

List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().limit(3).forEach(System.out::println);

3.6 skip操作

skip操作用于跳过Stream流中的前n个元素。

List<String> list = Arrays.asList("a", "b", "c", "d", "e");
list.stream().skip(2).forEach(System.out::println);

3.7 sorted操作

sorted操作用于对Stream流中的元素进行排序。它有两种形式:一种是使用自然顺序排序,另一种是使用自定义比较器排序。

List<String> list = Arrays.asList("a", "c", "b", "d", "e");
list.stream().sorted().forEach(System.out::println);

以上就是Java 8中Stream流的一些常用操作。

4. Stream流的终止操作

在Java 8中,Stream流的操作可以分为中间操作和终止操作。中间操作只对数据进行处理,但不会消费Stream流,而终止操作会消费Stream流,并产生一个结果或者一个副作用。以下是一些常用的终止操作:

4.1 forEach操作

forEach操作用于对Stream流中的每个元素执行一个操作。这是一个终止操作,所以它会消费Stream流。

List<String> list = Arrays.asList("a", "b", "c");
list.stream().forEach(System.out::println);

4.2 toArray操作

toArray操作用于将Stream流转换为数组。

List<String> list = Arrays.asList("a", "b", "c");
String[] array = list.stream().toArray(String[]::new);

4.3 reduce操作

reduce操作用于将Stream流中的元素通过一个二元函数进行累积操作,从而将Stream流减少为一个单一的结果。

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = list.stream().reduce(Integer::sum);

4.4 collect操作

collect操作用于将Stream流转换为其他形式的结果,如List、Set或Map。

List<String> list = Arrays.asList("a", "b", "c");
List<String> newList = list.stream().collect(Collectors.toList());

4.5 min, max, count, anyMatch, allMatch, noneMatch操作

这些操作用于对Stream流中的元素进行统计。

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> min = list.stream().min(Integer::compareTo);
Optional<Integer> max = list.stream().max(Integer::compareTo);
long count = list.stream().count();
boolean anyMatch = list.stream().anyMatch(i -> i > 3);
boolean allMatch = list.stream().allMatch(i -> i > 0);
boolean noneMatch = list.stream().noneMatch(i -> i < 0);

4.6 findFirst, findAny操作

这些操作用于获取Stream流中的某个元素。

List<String> list = Arrays.asList("a", "b", "c");
Optional<String> first = list.stream().findFirst();
Optional<String> any = list.stream().findAny();

以上就是Java 8中Stream流的一些常用终止操作。

5. Stream流的并行处理

在Java 8中,Stream API支持并行处理,这是一种利用多核处理器的能力来加速计算的技术。

5.1 并行流的概念

并行流就是一个把内容分成多个数据块,并用不同的线程分别处理每个数据块的流。Java 8的并行流就是把一个数据内容分成多个数据块,并用多个线程处理的流。这样可以充分利用多核处理器的优势,使得程序在进行大数据量处理时能更快地得到结果。

5.2 创建并行流

创建并行流有两种方式:

  1. 使用 parallelStream 方法:
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
Stream<String> parallelStream = list.parallelStream();
  1. 使用 parallel 方法:
List<String> list = Arrays.asList("a", "b", "c", "d", "e");
Stream<String> parallelStream = list.stream().parallel();

5.3 并行流的使用注意事项

虽然并行流可以提高处理速度,但并不是所有情况下都适用,并且并行流的使用也需要注意以下几点:

  1. 任务的性质:如果任务之间有大量的数据依赖性,那么并行流可能带来的性能提升就会大打折扣。

  2. 数据量的大小:只有在数据量足够大的情况下,使用并行流才能体现出性能优势。对于小数据量的处理,串行流可能更快。

  3. 并行处理可能引发的问题:并行处理可能会引发线程安全问题,需要确保操作是线程安全的。

  4. 并行流和顺序流的切换:并行流和顺序流可以相互切换。使用 parallel 方法可以将顺序流转换为并行流,使用 sequential 方法可以将并行流转换为顺序流。

  5. 注意避免线程阻塞:如果流中的某些操作可能会阻塞线程,如网络IO操作,那么使用并行流可能会导致程序性能下降,甚至发生死锁。

以上就是Java 8中Stream流并行处理的一些基本概念和使用注意事项。

以下是一些使用Java 8 Stream流进行数据处理的实例:

6.实战示例

实例1:过滤和转换

假设我们有一个用户列表,我们想要找出年龄大于18岁的用户,并将他们的用户名转换为大写。

public class User {
    private String username;
    private int age;

    // getters and setters
}

List<User> users = ... // 获取用户列表

List<String> usernames = users.stream()
    .filter(user -> user.getAge() > 18)
    .map(User::getUsername)
    .map(String::toUpperCase)
    .collect(Collectors.toList());

实例2:统计

假设我们想要统计用户列表中年龄大于18岁的用户数量。

long count = users.stream()
    .filter(user -> user.getAge() > 18)
    .count();

实例3:查找

假设我们想要找到年龄最大的用户。

Optional<User> oldestUser = users.stream()
    .max(Comparator.comparingInt(User::getAge));

实例4:并行处理

假设我们有一个非常大的用户列表,我们想要并行地处理这个列表,找出年龄大于18岁的用户,并将他们的用户名转换为大写。

List<String> usernames = users.parallelStream()
    .filter(user -> user.getAge() > 18)
    .map(User::getUsername)
    .map(String::toUpperCase)
    .collect(Collectors.toList());

以上就是一些使用Java 8 Stream流进行数据处理的实例。通过这些实例,我们可以看到Stream流提供了一种声明式的方式来处理数据,使得代码更加清晰和简洁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值