美文网首页
272. Java Stream API - 使用数字专用流,避

272. Java Stream API - 使用数字专用流,避

作者: Cache技术分享 | 来源:发表于2025-12-16 08:56 被阅读0次

272. Java Stream API - 使用数字专用流,避免装箱开销

我们知道,Java 中的 Stream<T> 处理的是对象,但如果你处理的是大量的数字(intlongdouble),就需要注意“装箱与拆箱(boxing/unboxing)”的问题。

🚫 问题:普通 Stream 会引发装箱性能问题

Stream<Integer> numbers = List.of(1, 2, 3, 4).stream(); // 每个 int 都是 Integer 对象
int sum = numbers.reduce(0, Integer::sum);             // 多次装箱与拆箱,性能不佳

✅ 解决方案:使用数字专用流

Java 提供了三个专用数字流接口来避免装箱开销:

  • IntStream:处理 int 值流
  • LongStream:处理 long 值流
  • DoubleStream:处理 double 值流

它们使用的是原始类型(primitive types,不会自动装箱,性能更高。


📊 IntStream 示例:终端操作更丰富

import java.util.stream.IntStream;

public class StatExample {
    public static void main(String[] args) {
        IntStream stream = IntStream.of(10, 20, 30, 40, 50);

        int sum = stream.sum(); // 🚀 无装箱,高效计算
        System.out.println("Sum: " + sum); // 输出:Sum: 150
    }
}

数字流接口提供了一些 Stream<T> 没有的终端操作:

方法名 描述
sum() 计算总和
min(), max() 查找最小值和最大值
average() 计算平均值(返回 OptionalDouble
summaryStatistics() 返回一个统计对象:总数、最小、最大、平均、总和

🧮 summaryStatistics() 示例

IntSummaryStatistics stats = IntStream.of(10, 20, 30, 40)
    .summaryStatistics();

System.out.println("Count: " + stats.getCount());
System.out.println("Sum: " + stats.getSum());
System.out.println("Average: " + stats.getAverage());
System.out.println("Min: " + stats.getMin());
System.out.println("Max: " + stats.getMax());

输出:

Count: 4
Sum: 100
Average: 25.0
Min: 10
Max: 40

🎯 只需遍历一次数据流,五个指标一次到位!


✅ 最佳实践:使用 Stream 的注意事项

使用 Stream 时,以下行为要避免或注意,以确保安全性、可读性和性能。


⚠️ 一、不要复用 Stream 对象

错误示例:

Stream<String> stream = List.of("A", "B", "C").stream();

var upper = stream.map(String::toUpperCase);
var list = stream.toList(); // ❌ 第二次使用同一个 stream,会抛异常!

正确示例:

List<String> data = List.of("A", "B", "C");

var upper = data.stream().map(String::toUpperCase).toList();
var lower = data.stream().map(String::toLowerCase).toList(); // ✅ 每次新建 stream

📌 流只能使用一次,操作完就“关闭”了。


⚠️ 二、不要把 Stream 存成字段或变量长期保留

为什么?
Stream 是连接到数据源的“流水线”,并不存储数据。如果保存到字段中,容易:

  • 被重复使用引发错误
  • 引入副作用
  • 增加代码难以追踪的数据流动问题

✅ 最佳实践:流应就地创建、就地消费!

// ✅ 好做法
List<Integer> result = List.of(1, 2, 3).stream()
    .map(i -> i * 2)
    .filter(i -> i > 3)
    .toList();

⚠️ 三、避免对流外部变量产生副作用

int[] total = {0};

List.of(1, 2, 3).stream().forEach(i -> total[0] += i); // ❌ 修改外部变量,副作用!

System.out.println(total[0]);

这段代码虽然能运行,但它:

  • 破坏了函数式编程的纯粹性
  • 在并行流中(parallel stream)可能导致竞态条件(race condition)

✅ 推荐写法:

int sum = List.of(1, 2, 3).stream()
    .mapToInt(Integer::intValue)
    .sum(); // ✅ 无副作用

✅ 总结小贴士

规则 原因
✔ 使用 IntStream、LongStream、DoubleStream 避免装箱,提高数字处理性能
✔ 每次新建 stream,不要重复使用同一个 Stream 一次性消费,不能重复使用
✔ 不要把 stream 存成字段或变量长期保留 增加代码复杂性,并可能导致使用错误
✔ 避免修改外部变量(无副作用) 保持函数式风格,保证线程安全
✔ 中间操作返回新 stream,不会立刻执行 执行在终端操作触发时才发生

相关文章

  • Stream

    使用 Stream API 高逼格 优化 Java 代码 Java8 Stream流中的 collect() 别再...

  • jdk8 Stream流

    jdk8 Stream流 1.Stream API 简介 Stream API是Java 8中加入的一套新的API...

  • java stream api中的reduce方法使用

    java stream api中的reduce方法使用 java stream api是对函数式编程的支持,虽然s...

  • Java 8 Stream Study

    Java 8 Stream Study Java 8 Stream Java 8 API添加了一个新的抽象称为流S...

  • 【Java 8实战笔记】为什么要关心Java 8

    概述部分 使用Java8新的API,流(Stream),它支持许多处理数据的并行操作,由Stream库来选择最佳低...

  • java 函数式编程 之 Stream API (二)

    在上一篇文章中,我们介绍了java8 中 stream API 的简单使用,其中包括对于stream流操作的相关方...

  • Stream

    Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。 Stream 使用一...

  • 探索Java8:(一)Stream的使用

    Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。 Stream 使用一...

  • java学习:java8新特性之一,Stream

    Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。 Stream 使用一...

  • Java 8 Stream

    Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。 Stream 使用一...

网友评论

      本文标题:272. Java Stream API - 使用数字专用流,避

      本文链接:https://www.haomeiwen.com/subject/rtfbcstx.html