【Stream 流】通过一个例子看遍所有Stream API使用场景

前言

上篇文章记录了方法引用,Lambda表达式等基础的知识点,这篇文章主要结合课设项目详细介绍Stream 流的API以及它的主要场景。

在这里插入图片描述

Stream API作用

在Java 8及其以后的版本中,Stream API为处理集合数据提供了强大而灵活的功能。有了Stream API,我们可以以一种声明式的方式对数据进行过滤、映射、排序、聚合等众多操作。

Stream API使用

话不多说,接下来看一下我们毕设中的一个场景。我们现在有一个电商平台的订单系统,其中有一个Order类,它包含订单号、商品名称、价格和下单时间等属性。现在,我们有一个订单列表,并希望对这个列表进行各种操作。

Order类都有这些属性和方法:

import java.time.LocalDateTime;  
import java.util.*;  
  
class Order {  
    private String orderId;  
    private String productName;  
    private double price;  
    private LocalDateTime orderTime;  
  
    // 构造方法、getter和setter这里省略  
    //重写equals方法
    @Override  
    public boolean equals(Object o) {  
        if (this == o) return true;  
        if (o == null || getClass() != o.getClass()) return false;  
        Order order = (Order) o;  
        return Double.compare(order.price, price) == 0 &&  
                Objects.equals(orderId, order.orderId) &&  
                Objects.equals(productName, order.productName) &&  
                Objects.equals(orderTime, order.orderTime);  
    }  
  //重写HashCode方法
    @Override  
    public int hashCode() {  
        return Objects.hash(orderId, productName, price, orderTime);  
    }  
  //重写toString方法
    @Override  
    public String toString() {  
        return "Order{" +  
                "orderId='" + orderId + '\'' +  
                ", productName='" + productName + '\'' +  
                ", price=" + price +  
                ", orderTime=" + orderTime +  
                '}';  
    }  
}

有了属性和方法的类之后,我们就可以创建一个订单列表,润润喉来演示Stream API的多个方法了。

过滤(使用filter方法)

需求:找出价格大于100的订单:

List<Order> orders =  ...   //这个不重要,省略
List<Order> expensiveOrders = orders.stream()  
    .filter(order -> order.getPrice() > 100)  
    .collect(Collectors.toList());

映射(使用map方法)

需求:提取所有订单的商品名称,这里使用到了方法引用,引用Order类中的getProductName方法:

List<String> productNames = orders.stream()  
    .map(Order::getProductName)  
    .collect(Collectors.toList());

排序(使用sorted方法)

需求:按照价格对订单进行排序:

List<Order> sortedOrders = orders.stream()  
    .sorted(Comparator.comparingDouble(Order::getPrice))  
    .collect(Collectors.toList());

去重(使用distinct方法)

需求:订单列表中有重复订单(订单号相同代表着重复),我们去重后可以得到唯一的订单列表:

List<Order> uniqueOrders = orders.stream()  
    .distinct()  
    .collect(Collectors.toList());

这里需要注意:使用distinct方法去重,Order类必须正确实现equals和hashCode方法,在咱们上面创建的类中可查看详情。

计数(使用count方法)

需求:统计订单列表中订单的数量:

long orderCount = orders.stream()  
    .count();

聚合(使用reduce方法)

需求:计算订单列表中所有订单的总价格:

double totalPrice = orders.stream()  
    .mapToDouble(Order::getPrice)  
    .sum();

或使用reduce方法:

OptionalDouble totalPriceOptional = orders.stream()  
    .mapToDouble(Order::getPrice)  
    .reduce(Double::sum);  
double totalPrice = totalPriceOptional.orElse(0);

任意匹配和所有匹配(使用anyMatch和allMatch方法)

需求:检查是否有价格超过200的订单:

boolean hasExpensiveOrder = orders.stream()  
    .anyMatch(order -> order.getPrice() > 200);

检查所有订单的价格是否都大于0:

boolean areAllPricesValid = orders.stream()  
    .allMatch(order -> order.getPrice() > 0);

查找第一个/最后一个元素(使用findFirst和findAny方法)

需求:查找价格最高的订单(假设订单已按价格排序):

Optional<Order> mostExpensiveOrder = orders.stream()  
    .sorted(Comparator.comparingDouble(Order::getPrice).reversed())  
    .findFirst();

这里需要注意:在没有排序的情况下,findFirst返回的是流中的第一个元素,而findAny返回流中的任意元素。在并行流中,findAny通常比findFirst更高效。

扁平化流(使用flatMap方法)

需求:每个订单有一个商品列表,我们想要得到一个包含所有商品名称的流:

class Order {  
    //  属性和方法  
    List<String> productNames; // 假如每个订单有这个属性  
      
    // getter和setter  
}  
  
// 初始化orders列表这里也省略
  
Stream<String> allProductNames = orders.stream()  
    .flatMap(order -> order.getProductNames().stream());  
  
List<String> collectedProductNames = allProductNames.collect(Collectors.toList());

分组(使用collect方法和Collectors.groupingBy)

需求:按照商品价格区间对订单进行分组:

Map<String, List<Order>> groupedOrders = orders.stream()  
    .collect(Collectors.groupingBy(  
        order -> {  
            if (order.getPrice() <= 100) {  
                return "Cheap";  
            } else if (order.getPrice() <= 200) {  
                return "Medium";  
            } else {  
                return "Expensive";  
            }  
        }  
    ));

分区(使用collect方法和Collectors.partitioningBy)

需求:将订单按照价格是否超过100进行分区:

Map<Boolean, List<Order>> partitionedOrders = orders.stream()  
    .collect(Collectors.partitioningBy(order -> order.getPrice() > 100));

连接字符串(使用collect方法和Collectors.joining)

需求:将所有订单的商品名称连接成一个字符串,以逗号分隔:

String productNamesString = orders.stream()  
    .flatMap(order -> order.getProductNames().stream())  
    .collect(Collectors.joining(", "));

使用自定义收集器

需求:我们想要收集所有订单的价格到一个IntSummaryStatistics对象中,以便获取最大值、最小值、平均值等统计信息:

IntSummaryStatistics priceStats = orders.stream()  
    .mapToInt(Order::getPrice)  
    .summaryStatistics();  
  
System.out.println("Max price: " + priceStats.getMax());  
System.out.println("Min price: " + priceStats.getMin());  
System.out.println("Average price: " + priceStats.getAverage());

限制流的大小(使用limit方法)

需求:获取价格最高的前三个订单:

List<Order> top3ExpensiveOrders = orders.stream()  
    .sorted(Comparator.comparingDouble(Order::getPrice).reversed())  
    .limit(3)  
    .collect(Collectors.toList());

跳过流中的元素(使用skip方法)

需求:跳过前五个订单,然后获取剩余的订单:

List<Order> remainingOrders = orders.stream()  
    .skip(5)  
    .collect(Collectors.toList());

这些场景涵盖了Stream API中的大部分常用方法。咱们列举的也不少了,今天就列举到这里吧。

本篇文章到此结束,谢谢大家的观看!

在这里插入图片描述

  • 33
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论
### 回答1: Java StreamJava 8引入的一个新的API,用于处理集合(Collection)和数组(Array)数据。它提供了一种更简洁、更函数式的方式来操作数据,可以将数据的处理过程表达为一系列的操作步骤,而不需要使用传统的if语句。 Stream的操作可以通过一系列的方法链式调用来完成,其中包括过滤(filter)、转换(map)、排序(sorted)等操作。通过这些操作,我们可以对数据进行筛选、转换、排序等操作,而不需要使用繁琐的if语句。下面是一个简单示例,说明如何使用Stream替代if语句: 假设有一个存储了多个学生信息的List集合,每个学生对象包含了姓名(name)和成绩(score)两个属性。我们要找出成绩大于等于80的所有学生,并将其姓名打印出来。可以使用Stream来达到这个目的: List<Student> students = // 初始化学生信息的List集合 students.stream() .filter(student -> student.getScore() >= 80) // 过滤出成绩大于等于80的学生 .forEach(student -> System.out.println(student.getName())); // 打印学生姓名 通过这段代码,我们使用了filter方法来过滤出成绩大于等于80的学生,并使用forEach方法来打印学生的姓名。相比于传统的if语句,这种方式更简洁、更易读,同时也更符合函数式编程的思想。 总的来说,Java Stream提供了一种更简洁、更函数式的方式来处理集合和数组数据,可以替代一部分需要使用if语句的场景,使代码更加简洁、易读,提高代码的可维护性和可复用性。 ### 回答2: Java Stream可以用来替代一些繁琐的if条件判断语句,提高代码的可读性和简洁性。 Stream的优势在于提供了一种函数式编程的方式,通过链式调用一系列的操作来处理集合或数组中的元素。 举个例子,假设有一个存储学生信息的列表,我们要找出其中所有年龄大于18岁的男性学生。使用传统的if条件判断语句,代码可能会变得冗长且难以维护: ```java List<Student> students = ... // 学生信息列表 List<Student> maleStudentsOver18 = new ArrayList<>(); for (Student student : students) { if (student.getAge() > 18 && student.getGender().equals("男")) { maleStudentsOver18.add(student); } } ``` 而使用Stream,可以通过一行代码就实现同样的功能: ```java List<Student> maleStudentsOver18 = students.stream() .filter(student -> student.getAge() > 18 && student.getGender().equals("男")) .collect(Collectors.toList()); ``` 通过的filter()操作,我们可以设定筛选条件,只保留符合条件的学生对象。最后使用collect()操作将筛选结果收集到一个新的列表中。 相比于传统的if条件判断,Stream更加简洁和易于理解,减少了代码的复杂度。它将函数式编程的思想引入到Java中,提供了一种更加优雅和高效的数据处理方式。 ### 回答3: 在Java中,Stream可以用来替代一部分if语句的功能。StreamJava 8引入的一种函数式编程的概念,它提供了一种更简洁和灵活的方式来处理数据。 通过Stream,我们可以通过一系列的操作来处理集合或数组中的元素,而不需要显式地使用if语句进行条件判断。以下是几个利用Stream替代if的例子: 1. 过滤元素:使用filter操作可以根据某个条件过滤集合中的元素。例如,我们可以使用filter操作来筛选出年龄大于18岁的人:``` List<Person> adults = people.stream() .filter(person -> person.getAge() > 18) .collect(Collectors.toList()); ``` 2. 映射元素:使用map操作可以将集合中的元素映射为另一种类型。例如,我们可以将一个字符串集合中的元素转为大写字母:``` List<String> uppercaseNames = names.stream() .map(String::toUpperCase) .collect(Collectors.toList()); ``` 3. 判断是否存在元素:使用anyMatch操作可以判断集合中是否存在满足某个条件的元素。例如,我们可以判断是否有人的年龄大于18岁:``` boolean hasAdult = people.stream() .anyMatch(person -> person.getAge() > 18); ``` 4. 对集合中的元素进行计数:使用count操作可以统计集合中满足某个条件的元素个数。例如,我们可以统计年龄大于18岁的人数:``` long count = people.stream() .filter(person -> person.getAge() > 18) .count(); ``` 通过这些操作,我们可以更加简洁和优雅地处理集合中的元素,减少了if语句的使用。然而,也需要注意Stream并不是万能的,有些情况下仍然需要使用if语句来进行复杂的逻辑判断。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小威要向诸佬学习呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值