首页 > 编程语言 >一文掌握Java Stream API

一文掌握Java Stream API

时间:2023-10-28 17:02:58浏览次数:34  
标签:Java Stream stream 示例 List 列表 API 排序

一文掌握Java Stream API_List

引言

Java Stream API 自 Java 8 引入以来,已成为处理集合数据的强大工具。它不仅提高了代码的可读性,还优化了性能,使得集合操作变得更加简洁和高效。本文将深入探讨如何利用 Stream API 的常用操作,帮助你更好地掌握这一强大的功能。

Java Stream API 简介

Java Stream 是 Java 8 引入的一种新的抽象层,专门用于简化集合对象的处理过程。它提供了一种更加简洁和函数式的方式来处理数据,使得开发者能够编写出更加清晰和易于维护的代码。Stream 操作可以是中间操作,也可以是终端操作,中间操作返回的是Stream,所以我们可以链式调用;终端操作返回的是一个结果或者是null。

示例:
假设我们有一个 Person 类,其中包含 nameage 两个属性,现在我们有一个 Person 对象的列表,我们想要找出其中年龄大于20的所有人,并按照年龄升序排序。

List<Person> people = Arrays.asList(
    new Person("Alice", 23),
    new Person("Bob", 20),
    new Person("Charlie", 24)
);
// 使用Stream进行过滤和排序
List<Person> result = people.stream()
.filter(person -> person.getAge() > 20) // 过滤出年龄大于20的人
.sorted(Comparator.comparing(Person::getAge)) // 根据年龄升序排序
.collect(Collectors.toList()); // 收集结果到一个列表中// 输出结果
result.forEach(System.out::println);

在这个示例中,我们首先创建了一个包含三个 Person 对象的列表。然后,我们调用 stream() 方法将列表转换为 Stream。接下来,我们使用 filter 方法来过滤出年龄大于20的人,使用 sorted 方法根据年龄进行升序排序,最后使用 collect 方法将结果收集到一个新的列表中。

超级常用操作

求交集和差集

通过使用 filter 和 map 方法,我们可以轻松地实现这些集合操作,从而提高代码的可读性和效率。

示例:
假设我们有两个整数列表,我们想要找出这两个列表的交集和差集。

List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> list2 = Arrays.asList(4, 5, 6, 7, 8);

// 求交集
List<Integer> intersection = list1.stream()
    .filter(list2::contains) // 筛选出同时存在于list2中的元素
    .collect(Collectors.toList()); // 收集结果到一个新的列表
    
System.out.println("交集: " + intersection);

// 求差集
List<Integer> difference = list1.stream()
    .filter(element -> !list2.contains(element)) // 筛选出不存在于list2中的元素
    .collect(Collectors.toList()); // 收集结果到一个新的列表

System.out.println("差集: " + difference);

在这个示例中,我们首先定义了两个整数列表 list1list2。然后,我们使用 stream() 方法将 list1 转换为 Stream。接下来,我们使用 filter 方法来筛选出同时存在于 list2 中的元素,从而得到两个列表的交集。同样地,我们使用 filter 方法来筛选出不存在于 list2 中的元素,从而得到 list1 相对于 list2 的差集。最后,我们使用 collect 方法将结果收集到新的列表中,并打印出交集和差集。

排序

在Java的Stream API中,sorted()方法提供了一种快捷且灵活的方式来对集合中的元素进行排序。这个方法可以直接对元素进行自然排序,或者通过提供一个自定义的比较器来实现定制排序。这种操作对于处理大量数据时尤其有用,因为它允许开发者以声明式的方式来表达排序逻辑,而不是手动实现排序算法。

  • 示例:
    假设我们有一个学生列表,每个学生都有姓名和分数两个属性,我们想要根据分数对学生进行升序排序。
List<Student> students = Arrays.asList(
    new Student("Alice", 90),
    new Student("Bob", 85),
    new Student("Charlie", 92)
);
// 使用Stream进行排序
List<Student> sortedStudents = students.stream()
    .sorted(Comparator.comparingInt(Student::getScore)) // 根据分数进行升序排序
    .collect(Collectors.toList()); // 收集排序后的结果// 输出排序后的学生信息
    sortedStudents.forEach(student -> System.out.println(student.getName() + ": " + student.getScore()));

在这个示例中,我们首先创建了一个包含三个 Student 对象的列表。然后,我们调用 stream() 方法将列表转换为 Stream。接下来,我们使用 sorted 方法并提供一个比较器,根据学生的分数进行升序排序。最后,我们使用 collect 方法将排序后的结果收集到一个新的列表中,并打印出每个学生的姓名和分数。

Stream.Builder

Stream.Builder 是 Java 8 引入的一个接口,用于更灵活地构建 Stream 流。与直接从集合或数组创建流相比,Stream.Builder 提供了一种逐个添加元素的方式,使得我们可以在构建流的过程中动态地添加元素,这在处理动态数据源或需要在运行时决定元素的场景下非常有用。

示例:
考虑一个场景,我们需要创建一个字符串流,并对这个流进行一系列的操作。我们可以使用 Stream.Builder 来逐个添加字符串元素,然后构建成一个流。

在这个示例中,我们首先创建了一个 Stream.Builder 对象,然后使用 add 方法逐个添加了三个字符串元素。最后,我们调用 build 方法构建了一个流,并对这个流进行了遍历打印操作。

// 导入必要的类import java.util.stream.Stream;

// 主类定义public class StreamBuilderExample {
    // 主函数
    public static void main(String[] args) {
        // 创建一个 Stream.Builder 对象
        Stream.Builder<String> builder = Stream.builder();
        // 逐个添加字符串元素到流构建器
        builder.add("zhangsan"); // 添加张三
        builder.add("lisi"); // 添加李四
        builder.add("wangmazi"); // 添加王麻子
        // 构建并获取流
        Stream<String> stream = builder.build();
        // 遍历流,打印每个元素
        stream.forEach(System.out::println);
    }
}

从数组创建流

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

示例

  • 假设有一个整数数组,我们想要找出其中的偶数,并将其乘以2。
  • 原始数组:[1, 2, 3, 4, 5, 6]
  • 操作后的结果:[4, 8, 12]
  • 代码片段
// 引入必要的包import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ArrayToStream {
    public static void main(String[] args) {
        // 定义一个整数数组
        int[] numbers = {1, 2, 3, 4, 5, 6};
        
        // 使用Arrays.stream()方法从数组创建流,然后进行过滤和映射操作
        List<Integer> result = Arrays.stream(numbers)
                                     .filter(n -> n % 2 == 0) // 过滤出偶数
                                     .map(n -> n * 2) // 将偶数乘以2
                                     .boxed() // 将IntStream转换为Stream<Integer>
                                     .collect(Collectors.toList()); // 将结果收集到列表中
        
        // 输出结果
        System.out.println(result); // 输出:[4, 8, 12]
    }
}

从集合创建流

可以通过调用集合的stream()方法直接获取一个流对象。

示例

  • 假设有一个人名列表,我们想要找出长度大于3的人名,并将其转换为大写。
  • 原始列表:["Tom", "Jerry", "Alice", "Bob", "Catherine"]
  • 操作后的结果:["JERRY", "ALICE", "CATHERINE"]
  • 代码片段
List<String> names = Arrays.asList("Tom", "Jerry", "Alice", "Bob", "Catherine");
List<String> filteredNames = names.stream()
                                  .filter(name -> name.length() > 3)
                                  .map(String::toUpperCase)
                                  .collect(Collectors.toList());

迭代中使用元素索引

在Java 8的Stream API中,直接获取正在迭代的元素的索引并不是一件直接的事情。但是,我们可以通过一些间接的方法来实现这一点,比如使用 IntStreammapToObj 方法。这样做不仅使代码更加灵活,而且还保持了代码的简洁性和可读性。

示例:
假设我们有一个字符串列表,我们想要打印出每个字符串及其在列表中的索引。

List<String> words = Arrays.asList("zhangsan", "lisi", "wangmazi");

// 使用IntStream和mapToObj进行迭代
IntStream.range(0, words.size())
  .mapToObj(index -> "索引: " + index + ", 值: " + words.get(index))  // 获取索引和对应的值
  .forEach(System.out::println);  // 打印结果

在这个示例中,我们首先定义了一个包含三个字符串的列表 words。然后,我们使用 IntStream.range 方法创建一个从0到 words.size() 的整数流,其中每个整数代表一个索引。接下来,我们使用 mapToObj 方法将每个索引映射到一个字符串,这个字符串包含索引和对应的列表元素。最后,我们使用 forEach 方法来打印出结果。

总结

通过本文的介绍,你应该已经掌握了如何使用 Java Stream API 进行集合操作,包括求交集和差集等。掌握这些技能不仅能够提升你的编程效率,还能帮助你写出更加简洁、高效的代码。

标签:Java,Stream,stream,示例,List,列表,API,排序
From: https://blog.51cto.com/u_16326109/8072247

相关文章

  • Java面试专题
    Java面试专题面试题背后的逻辑->拆分问题讲解->回答方式及参考问题Redis篇使用场景1、你在最近的项目中哪些场景使用了redis?缓存:缓存击穿,缓存穿透,缓存雪崩,双写一致性,数据过期策略,数据淘汰策略分布式锁:setnx,redission2、什么是缓存穿透,怎么解决?缓存穿透:查询一个不存在......
  • javaweb--JDBC的API-Connection
    1、获取执行SQL对象2、管理事务setAutoCommit(bool)true为自动提交false为手动提交commit()提交事务rollback()回滚事务packagecom.avb.jdbc;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.SQLException;importjava.sql.Statement;public......
  • Java-全网最详细反射
    Java-反射前言Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动......
  • Java基础 多线程的 6 种状态
       Java的虚拟机当中没有定义运行状态,因为当线程抢夺到CPU执行权的时候,虚拟机会把当前线程交给操作系统管理,虚拟机就不管了。 ......
  • javaweb--JDBC的API-DriverManager
    DriverManager可以实现的功能1、注册驱动ClassforName("com.mysql.jdbc.Driver");查看Driver类源码在静态代码块中会运行DriverManager类mysql5以后的驱动包可以省略注册驱动步骤2、获取连接java:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2...jdbc:my......
  • Java基础 阻塞队列的方式实现等待唤醒机制,哪里体现了等待?哪里又体现了唤醒?
    Java的阻塞队列(BlockingQueue)可以用来实现等待唤醒机制,其中等待和唤醒的操作在队列的不同方法中体现:1.等待:在阻塞队列中,等待通常发生在以下情况:2.当队列为空时,消费者线程试图从队列中取出元素时,它会被阻塞,直到队列中有元素可供消费。这种等待是通过阻塞队列的take()方法来实现......
  • javaweb学习每日总结-第八天
    第八天学习Springboot今天也终于是学到了springboot的技术,springboot是一款Java开发的框架,也是当下最流行的开发方式,没有之一!今天我进行了springboot技术的入门,初步了解了springboot技术的发展和应用,也用idea写了一个最简单的springboot程序。除此之外,我还下载了postmen这个软......
  • javaweb--JDBC入门
    packagecom.avb.jdbc;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.Statement;publicclassjdbcdemo{publicstaticvoidmain(String[]args)throwsException{//注册驱动Class.forName("com.mysql.jdbc.D......
  • Java基础 等待唤醒机制(阻塞队列方式实现)
    等待唤醒机制还可以用阻塞队列的方式进行实现    练习:利用阻塞队列完成生产者和消费者(等待唤醒机制)的代码细节:生产者和消费者必须使用同一个阻塞队列阻塞队列的创建方式(泛型:队列里面数据的类型):ArrayBlockingQueue<String> queue = new  ArrayBlockingQueue<......
  • Java基础 什么是生产者和消费者
    在Java中,"生产者-消费者"(Producer-Consumer)是一种常见的并发编程模型,用于协调多个线程之间的工作,其中一些线程充当生产者,而其他线程充当消费者。这模型通常用于处理共享数据的情况,其中生产者线程生成数据并将其放入共享缓冲区,而消费者线程则从缓冲区中取出数据并进行处理。主要特......