侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

使用Stream API处理多层嵌套集合并避免空指针

2025-12-13 / 0 评论 / 4 阅读

题目

使用Stream API处理多层嵌套集合并避免空指针

信息

  • 类型:问答
  • 难度:⭐⭐

考点

Stream API,Optional处理,空指针安全,方法引用,Lambda表达式

快速回答

核心解决方案:

  • 使用flatMap展开嵌套集合
  • Optional.ofNullable()包装可能为null的集合
  • 通过mapToDoublesum计算总和
  • 使用DecimalFormat格式化结果
  • 结合方法引用(::)简化代码
## 解析

问题场景

在实际业务中常需处理多层嵌套数据结构(如订单系统),需避免空指针异常并高效计算。给定以下类结构:

class Order {
    private List<OrderItem> items;  // 可能为null
    // getter省略
}

class OrderItem {
    private Double price;  // 可能为null
    private Integer quantity;  // 可能为null
    // getters省略
}

要求计算所有订单中有效订单项的总金额(price*quantity),返回保留两位小数的字符串,无订单时返回"0.00"。

解决方案与代码

public String calculateTotal(List<Order> orders) {
    double total = Optional.ofNullable(orders)
        .orElse(Collections.emptyList())
        .stream()
        .flatMap(order -> Optional.ofNullable(order.getItems())
            .orElse(Collections.emptyList()).stream())
        .filter(item -> item.getPrice() != null && item.getQuantity() != null)
        .mapToDouble(item -> item.getPrice() * item.getQuantity())
        .sum();

    return new DecimalFormat("0.00").format(total);
}

核心原理

  • 空指针防护Optional.ofNullable()包装可能为null的集合,结合orElse()返回空集合
  • 嵌套展开flatMap将每个Order的items展开为单一Stream
  • 过滤无效数据filter移除price或quantity为null的项
  • 数值计算mapToDouble转换为原始类型流避免装箱开销,sum()高效求和

最佳实践

  • 优先使用orElse(emptyList)而非orElseGet(ArrayList::new)减少对象创建
  • mapToDouble替代map+reduce,性能更优
  • DecimalFormat线程安全,适合金额格式化
  • filter中显式检查null,防御性编程

常见错误

  • 直接操作null集合orders.stream()在orders为null时抛出NPE
  • 忽略嵌套null:未处理order.getItems()为null的情况
  • 使用并行流不当:小数据量用parallelStream()可能降低性能
  • 多次遍历Stream:重复操作同一Stream会导致IllegalStateException

扩展知识

  • Java 9增强Optional.stream()可进一步简化为:
    .flatMap(order -> Optional.ofNullable(order.getItems()).stream())
  • 替代方案:使用Objects.requireNonNullElse()(Java 9+)替代Optional.orElse()
  • 性能考量:超大数据集考虑使用Collectors.summingDouble()并行收集
  • 金额精度:生产环境建议用BigDecimal替代double避免精度丢失