本文介绍如何利用 supplier 和 stream 的惰性求值特性,在 java stream 中延迟执行高开销方法(如数据库查询或远程调用),仅当上游数据未命中时才触发,避免不必要的性能损耗。
在使用 Java Stream 处理数据流时,若需“先查本地缓存,未命中再调用昂贵方法获取补充数据”,关键在于确保昂贵操作不被提前执行。常见误区是直接将 expensive().stream() 传入 Stream.concat() —— 此时 expensive() 会在流构建阶段立即调用,违背了“按需执行”的初衷。
核心思想是:不直接传递 List>
以下是推荐的简洁、可读性强的单行式实现:
public static OptionalfindTarget(String input, List myList) { return Stream. >>of( () -> myList, () -> expensive()) .flatMap(supplier -> supplier.get().stream()) .filter(o -> o.hasName(input)) .findFirst(); }
? 注意类型推导:Stream.of(...) 显式指定了泛型,避免编译器因 lambda 类型模糊导致推断失败(尤其在较旧 JDK 版本中)。
配合如下测试代码:
record MyObject(String s) {
public boolean hasName(String in) { return s.equals(in); }
}
static List expensive() {
System.out.println("expensive() called"); // 仅在需要时打印
return List.of(new MyObject("z"));
}
public static void main(String[] args) {
List myList = List.of(new MyObject("a"));
System.out.println("case 1 (hit): " + findTarget("a", myList)); // 不打印 expensive()
System.out.println("case 2 (miss): " + findTarget("x", myList)); // 打印 expensive()
} 输出为:
case 1 (hit): Optional[MyObject[s=a]] case 2 (miss): expensive() called Optional.empty
✅ 完全符合预期:expensive() 仅在 myList 无匹配项时才被调用。
通过将数据源封装为 Supplier> 并结合 Stream.of(...).
flatMap(s -> s.get().stream()),我们以极简、函数式的方式实现了「短路式多源查找」,兼顾可读性、性能与 Java Stream 的惰性契约。这比手动拆分为两步 findFirst().or(...) 更优雅,也彻底消除了重复的过滤逻辑,是处理条件性数据加载场景的推荐范式。