如何仅使用Lambda表达式改写Java Stream目标查找代码?
如何将这段流式搜索代码改写为纯Lambda形式?
我编写以下代码并非出于实用目的,更多是出于好奇(顺便提一句,我知道标题不够好,但想不出更合适的,欢迎建议)。现有代码如下:
State next = Stream.generate(q::poll).takeWhile(Objects::nonNull) .filter(s -> { if (atGoal(s)) return true; s.expand().forEach(q::add); return false; }).findFirst().orElse(null);
若想将其改写为仅使用Lambda表达式的形式(避免代码块),我已写出如下代码,但希望能避免其中的anyMatch(b -> true)部分:
State goal = Stream.generate(fringe::poll).takeWhile(Objects::nonNull) .filter(s -> atGoal(s) || s.expand().map(fringe::add).anyMatch(b -> true)) .findFirst().orElse(null);
方案1:利用count()触发副作用并返回false
核心思路是通过count()遍历所有扩展元素(触发添加队列的副作用),再通过&& false确保这部分最终返回false,完全匹配原代码逻辑:
State goal = Stream.generate(fringe::poll) .takeWhile(Objects::nonNull) .filter(s -> atGoal(s) || (s.expand().map(fringe::add).count() > 0 && false)) .findFirst().orElse(null);
- 当
s是目标状态时,atGoal(s)为true,filter返回true,直接被findFirst捕获 - 当
s不是目标状态时,执行s.expand().map(fringe::add).count():遍历所有扩展元素并加入队列,随后count() > 0 && false最终返回false,filter过滤掉该元素,继续循环
方案2:用peek替代map更贴合语义
既然我们只是要执行“添加到队列”的副作用操作,用peek比map更合适,配合findAny().isPresent()触发执行,再通过&& false返回false:
State goal = Stream.generate(fringe::poll) .takeWhile(Objects::nonNull) .filter(s -> atGoal(s) || (s.expand().peek(fringe::add).findAny().isPresent() && false)) .findFirst().orElse(null);
peek(fringe::add)直接对每个扩展元素执行入队操作,无需映射为Boolean类型,语义更清晰- 无论
s.expand()是否为空,findAny().isPresent() && false都会返回false,确保非目标状态的元素被过滤
方案3:单行Lambda代码块(兼容Java所有版本)
如果允许Lambda使用代码块但保持单行形式,这是最直观且易读的写法,完全还原原代码逻辑:
State goal = Stream.generate(fringe::poll).takeWhile(Objects::nonNull).filter(s -> { boolean g = atGoal(s); if(!g) s.expand().forEach(fringe::add); return g; }).findFirst().orElse(null);
内容的提问来源于stack exchange,提问作者traveh
相关产品推荐
相关产品推荐

