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

前言

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

Stream API作用

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

Stream API使用

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

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

java 复制代码
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的订单:

java 复制代码
List<Order> orders =  ...   
List<Order> expensiveOrders = orders.stream()  
    .filter(order -> order.getPrice() > 100)  
    .collect(Collectors.toList());

映射(使用map方法)

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

java 复制代码
List<String> productNames = orders.stream()  
    .map(Order::getProductName)  
    .collect(Collectors.toList());

排序(使用sorted方法)

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

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

去重(使用distinct方法)

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

java 复制代码
List<Order> uniqueOrders = orders.stream()  
    .distinct()  
    .collect(Collectors.toList());

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

计数(使用count方法)

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

java 复制代码
long orderCount = orders.stream()  
    .count();

聚合(使用reduce方法)

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

java 复制代码
double totalPrice = orders.stream()  
    .mapToDouble(Order::getPrice)  
    .sum();

或使用reduce方法:

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

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

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

java 复制代码
boolean hasExpensiveOrder = orders.stream()  
    .anyMatch(order -> order.getPrice() > 200);

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

java 复制代码
boolean areAllPricesValid = orders.stream()  
    .allMatch(order -> order.getPrice() > 0);

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

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

java 复制代码
Optional<Order> mostExpensiveOrder = orders.stream()  
    .sorted(Comparator.comparingDouble(Order::getPrice).reversed())  
    .findFirst();

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

扁平化流(使用flatMap方法)

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

java 复制代码
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)

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

java 复制代码
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进行分区:

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

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

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

java 复制代码
String productNamesString = orders.stream()  
    .flatMap(order -> order.getProductNames().stream())  
    .collect(Collectors.joining(", "));

使用自定义收集器

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

java 复制代码
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方法)

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

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

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

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

java 复制代码
List<Order> remainingOrders = orders.stream()  
    .skip(5)  
    .collect(Collectors.toList());

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

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

复制代码
相关推荐
why1515 小时前
腾讯(QQ浏览器)后端开发
开发语言·后端·golang
浪裡遊5 小时前
跨域问题(Cross-Origin Problem)
linux·前端·vue.js·后端·https·sprint
声声codeGrandMaster5 小时前
django之优化分页功能(利用参数共存及封装来实现)
数据库·后端·python·django
呼Lu噜6 小时前
WPF-遵循MVVM框架创建图表的显示【保姆级】
前端·后端·wpf
bing_1586 小时前
为什么选择 Spring Boot? 它是如何简化单个微服务的创建、配置和部署的?
spring boot·后端·微服务
学c真好玩6 小时前
Django创建的应用目录详细解释以及如何操作数据库自动创建表
后端·python·django
Asthenia04126 小时前
GenericObjectPool——重用你的对象
后端
Piper蛋窝6 小时前
Go 1.18 相比 Go 1.17 有哪些值得注意的改动?
后端
excel7 小时前
招幕技术人员
前端·javascript·后端
盖世英雄酱581367 小时前
什么是MCP
后端·程序员