我相信你自己已经多次见过这种情况:
public SomeObject findSomeObject(Arguments args) {
SomeObject so = queryFirstSource(args); // the most likely source first, hopefully
if (so != null) return so;
so = querySecondSource(args); // a source less likely than the first, hopefully
if (so != null) return so;
so = queryThirdSource(args); // a source less likely than the previous, hopefully
if (so != null) return so;
// and so on
}
我们有不同的来源可以找到我们需要搜索的对象。例如,我们可以首先检查用户ID是否在特权用户列表中。如果不在,则检查用户ID是否在允许用户列表中。否则,返回null。(这不是最好的例子,但我希望它足够生动)。
Guava为我们提供了一些帮助程序来美化上述代码。
public SomeObject findSomeObject(Arguments args) {
// if there are only two objects
return com.google.common.base.Objects.firstNonNull(queryFirstSource(args), querySecondSource(args));
// or else
return com.google.common.collect.Iterables.find(
Arrays.asList(
queryFirstSource(args)
, querySecondSource(args)
, queryThirdSource(args)
// , ...
)
, com.google.common.base.Predicates.notNull()
);
}
但是,对于我们中的更有经验的人来说,可能会发现如果查询(即queryXXXXSource(args)
)需要一定的时间,则可能效果不佳。这是因为我们现在首先查询所有源,然后将结果传递给查找其中第一个不为 null
的结果的方法。
与第一个示例相比,在前者不返回任何内容时才评估下一个源的情况下,这种第二种解决方案可能看起来更好,但可能执行得更差。
这里是我的真正问题所在,也是我建议的地方,希望已经实现了它的基础,或者有人可能提出一个更聪明的解决方案。
简单来说:是否有人已经实现了类似 defferedFirstNonNull
(见下文)的功能?是否有一种使用新的Stream框架轻松实现此目的的简单 Java 解决方案?您能否提出另一种优雅的解决方案来实现同样的结果?
规则:允许使用 Java 8,以及像 Google 的 Guava 或 Apache 的 Commons Lang 等活跃维护和知名的第三方库,采用 Apache 许可证或类似的许可证(不包括 GPL!)。
建议的解决方案:
public SomeObject findSomeObject(Arguments args) {
return Helper.deferredFirstNonNull(
Arrays.asList(
args -> queryFirstSource(args)
, args -> querySourceSource(args)
, args -> queryThirdSource(args)
)
, x -> x != null
)
}
因此,方法defferedFirstNonNull
将逐个评估每个lambda表达式,一旦谓词(x -> x!= null
)为真(即我们找到了匹配项),该方法将立即返回结果并且不会查询任何其他源。
PS:我知道表达式args -> queryXXXXSource(args)
可以缩短为queryXXXXSource
。 但是,这样做会使建议的解决方案更难阅读,因为一眼看上去不清楚会发生什么。
Stream
,那么你可以直接调用Stream.of(source1, source2, ...)
而不是Arrays.asList(source1, source2, ...).stream()
。 - Helder Pereira