使用longpredicate可避免long与long间自动装箱/拆箱开销,因predicate泛型不支持原始类型,每次test(long)均触发拆箱,高频场景下引发显著gc压力和cpu开销;而longpredicate专为long设计,配合longstream使用才能真正提升性能。

直接用 LongPredicate 替代 Predicate<long></long>,能彻底避免 long 和 Long 之间的自动装箱/拆箱开销——尤其在高频过滤(如日志时间戳、ID 匹配、数值聚合)场景下,性能差异可达 2–5 倍。
为什么不用 Predicate 处理 long 数据?
Java 的泛型不支持原始类型,Predicate<long></long> 强制要求参数是包装类 Long。每次调用 test(Long) 都会触发一次拆箱(longValue()),而流中成千上万个元素反复执行,就会累积显著的 GC 压力和 CPU 开销。
- 错误写法:
stream.filter((Long x) -> x > 1000L)→ 每次都拆箱 - 正确写法:
stream.mapToLong(x -> x.getId()).filter(id -> id > 1000L)→ 先转原始流,再用LongPredicate
LongPredicate 的三种典型使用方式
LongPredicate 只有一个抽象方法 test(long value),必须配合原始类型流(LongStream)或显式转换使用:
- 从
List<long></long>构建LongStream后过滤:list.stream().mapToLong(Long::longValue).filter(new LongPredicate() { public boolean test(long value) { return value % 100 == 0; } }) - 用 lambda 直接写:
LongPredicate isEven = l -> (l & 1L) == 0L;(位运算比% 2 == 0更快) - 配合
Arrays.stream(long[]):原始数组无需装箱,天然适配LongPredicate
和 IntPredicate / DoublePredicate 的关键区别
三者都是为避免装箱设计的专用谓词,但行为边界不同:
-
IntPredicate:只接受int,超范围值(如Integer.MAX_VALUE + 1L)会静默截断,需自行校验 -
LongPredicate:接受完整long范围(−2⁶³ 到 2⁶³−1),适合时间戳、分布式 ID 等大数场景 -
DoublePredicate:注意浮点精度问题,test(0.1 + 0.2)不等于test(0.3),慎用于等值判断
容易被忽略的兼容性陷阱
别指望 LongPredicate 能直接塞进 Stream<t></t> 的 filter()——它类型不匹配。常见误操作包括:
- 试图传给
stream.filter(myLongPredicate)→ 编译失败:no suitable method found for filter(LongPredicate) - 用
mapToLong后忘了收尾:漏掉.boxed()或.toArray()导致无法转回对象集合 - 在需要返回
List<long></long>的场景里,硬套LongStream→ 必须显式调用.boxed().collect(Collectors.toList()),此时又引入装箱,得不偿失
真正省性能的地方,是那些原本就处理原始数值、且终端操作也是原始类型的场景,比如统计、求和、找极值——这时候 LongPredicate 才真正物尽其用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











