IntPredicate 通过 boolean test(int value) 签名避免装箱拆箱,参数为栈上原始 int 类型;而 Predicate<Integer> 每次调用需拆箱、可能再装箱,增加 GC 压力。

IntPredicate 直接操作 int 值,从签名层面绕过 Integer 对象创建,彻底避免装箱拆箱。
为什么普通 Predicate<Integer> 会触发装箱拆箱
当你写 Predicate<Integer> p = n -> n > 10 并用于处理大量整数时:
- 输入参数
n是Integer类型,意味着每次调用都要从堆中取对象(哪怕来自缓存) - 执行
n > 10时,JVM 自动调用n.intValue()拆箱 - 若后续再把结果塞进集合或传给其他泛型方法,可能再次装箱
- 频繁的小对象分配还会增加 GC 压力
IntPredicate 的底层设计优势
IntPredicate 接口定义的是 boolean test(int value) —— 参数和返回值全是原始类型:
- 方法签名不涉及任何引用类型,编译器不会插入
valueOf()或intValue() - 参数
value在栈上直接传递,零对象开销 - 配合
IntStream使用时,整个数据流全程保持原始类型形态
典型优化场景与写法对比
比如筛选 1 到 1 亿中的偶数并求和:
立即学习“Java免费学习笔记(深入)”;
- ❌ 低效写法(隐式装箱):
Stream.iterate(1, i -> i + 1).limit(100_000_000)<br> .filter(n -> n % 2 == 0).mapToInt(Integer::intValue).sum();
—— 每次迭代都 new Integer,再拆箱,再装箱 Boolean - ✅ 高效写法(零装箱):
IntStream.rangeClosed(1, 100_000_000)<br> .filter((int n) -> n % 2 == 0).sum();
——filter接收的就是IntPredicate,n是栈上 int
扩展用法:自定义逻辑也能保持原始类型语义
你可以直接实现或用 Lambda 构造 IntPredicate,无需转型:
IntPredicate isPrime = n -> { /* 对 int n 做素数判断 */ };listOfInts.stream().mapToInt(Integer::intValue)<br> .filter(isPrime).forEach(System.out::println);
- 只要上游是
IntStream或通过mapToInt转成 int 流,下游所有操作都维持原始类型链路



















