optionalint 和 optionallong 是独立值类型,无泛型擦除、不支持 map/flatmap,仅存原始值+ispresent 标志;适用于需显式表达“可能不存在”语义的高性能数值场景。

OptionalInt 和 OptionalLong 不是 Optional 的语法糖
它们是独立的值类型,没有泛型擦除开销,也不支持链式调用 map、flatMap 等高阶操作——因为内部不持对象引用,而是直接存 int 或 long 值 + 一个 isPresent 标志位。
常见错误现象:OptionalInt.of(null) 编译失败;OptionalInt.empty().get() 抛 NoSuchElementException;误以为能像 Optional 那样传入 lambda 做转换。
-
OptionalInt只接受原始int,不能传Integer(自动拆箱会 NPE) -
OptionalLong同理,OptionalLong.of(100L)合法,OptionalLong.of(null)直接报错 - 没有
orElseGet(Supplier)的重载版本,只有orElse(int/long)和orElseThrow() - 性能上比
Optional<integer></integer>略优(无装箱/拆箱),但仅在高频调用且确定值非 null 场景下值得权衡
什么时候该用 OptionalInt / OptionalLong,而不是 Integer / Long 包装类
核心判断点:你是否真需要表达「这个 int/long 值可能不存在」的语义,且调用方必须显式处理空状态。
使用场景举例:计算数组最大值(可能为空)、Stream 的 max()/min() 结果、数据库字段映射为可空数值列。
立即学习“Java免费学习笔记(深入)”;
- 如果只是想避免
null,用int默认值(如 -1)或@Nullable注解更轻量 - 如果后续要 map 转换(比如
int → String),优先选Optional<integer></integer>,别硬套OptionalInt -
OptionalInt的ifPresent(IntConsumer)是唯一带副作用的消费方式,无法返回新值 - JDBC 中
ResultSet.getInt()返回 0 表示 null?错。应配合wasNull()判断,此时封装成OptionalInt才有意义
容易踩的坑:和 Stream API 混用时的隐式装箱
Stream.mapToInt 返回的是 IntStream,其 max() 返回 OptionalInt;但若你不小心用了 map(而非 mapToInt),就掉进 Optional<integer></integer> 的世界了——两者不可互转,也不能直接比较。
错误现象:stream.map(x -> x.value).max(Integer::compareTo) 返回 Optional<integer></integer>,而你想用 orElse(0) 却发现类型不匹配。
-
IntStream.max()→OptionalInt;Stream<integer>.max()</integer>→Optional<integer></integer> - 没有
OptionalInt.stream()方法,不能直接塞进下游流处理;得先ifPresent或转成Optional.of(value) - 别试图用
OptionalInt.ofNullable(...)—— 这个方法根本不存在,OptionalInt没有 nullable 构造入口 - 和 Jackson 序列化打交道时,默认不支持
OptionalInt,需注册自定义模块或改用包装类
替代方案其实更常用:用 Optional + 显式判空
除非你在写高性能数值聚合库,否则日常开发中,Optional<integer></integer> 的灵活性远胜原始类型特化版。
它支持 map、filter、orElseGet、与 Spring 的 @RequestParam(required = false) 天然契合,还便于单元测试 mock。
-
OptionalInt的getAsInt()强制要求值存在,没提供安全的默认转换逻辑 - 团队协作时,
Optional<integer></integer>更易理解,新人不会困惑「为什么这里不能用 lambda」 - Android 开发注意:API 24+ 才完整支持
OptionalInt,低版本需兼容处理 - 如果你已在用 Lombok,
@Builder.Default private OptionalInt flag = OptionalInt.empty();会编译失败——Lombok 不识别原始 Optional 类型
真正麻烦的不是选哪个类,而是忘了它们之间不能隐式转换,也忘了原始类型 Optional 没有泛型那种“统一抽象”。一旦混进 Stream 链或跨模块传递,类型边界就立刻暴露出来。









