intconsumer通过void accept(int value)签名实现零装箱开销,jvm按值传递、栈上操作;需配合int[]/intstream源头、原始类型集合及避免循环内调用包装类api才能真正生效。

IntConsumer 通过方法签名直接使用 int 原始类型,从调用起点就绕过 Integer 对象创建,实现零装箱开销。
签名层面杜绝装箱入口
它的唯一抽象方法是 void accept(int value),参数明确为原始 int。JVM 按值传递,数据在栈上操作,不涉及堆分配、Integer.valueOf() 或任何隐式对象构造。
- 对比
Consumer<integer></integer>:传入int会强制装箱;传入Integer后续运算又常需拆箱 -
IntConsumer的 lambda 写法如i -> System.out.println(i),编译后字节码直接操作ILOAD/IADD等整数指令
批处理中避开隐式装箱陷阱
即使接口本身不装箱,lambda 体内的错误写法仍会触发装箱——这是高频循环中最常见的性能回退点。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 避免在 lambda 中调用需要引用类型的 API:如
list.add(i)、map.put(i, "x")、String.valueOf(i)(后者虽不 new 对象,但若用于日志拼接或集合操作,仍可能连带引发装箱) - 若必须存入集合,不要在循环内做;改为先用
int[]缓存,批量处理完再统一转换 - 状态标记、索引计数、临时计算变量一律用
int,不声明Integer局部变量
配合原始类型生态使用才真正生效
IntConsumer 不是孤立优化,它需嵌入原始类型链路才能发挥全部价值:
- 源头数据来自
int[]或IntStream,而非List<integer></integer> - 下游消费方也应支持原始类型,例如用
SparseArray(Android)或IntObjectHashMap(Eclipse Collections),而非HashMap<integer v></integer> - 日志输出改用占位符:
log.info("value={}", i)(SLF4J)或封装工具方法,避免"value=" + i触发StringBuilder.append(int)内部的Integer.valueOf()
典型误用与修正对照
以下代码看似简洁,实则每轮都装箱:
❌ 错误写法(循环内装箱)IntConsumer printer = i -> list.add(i); // i → Integer.valueOf(i)numbers.forEach(printer);✅ 正确写法(保持原始类型流int[] raw = numbers.toArray(); // 假设 numbers 是 int[] 或 IntStreamfor (int i : raw) { /<em> 直接用 i </em>/ }// 或用 IntConsumer 处理纯数值逻辑,不碰包装类集合
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










