lor*_*llo 21 java coalesce lazy-evaluation
我有很多功能:
String first(){}
String second(){}
...
String default(){}
Run Code Online (Sandbox Code Playgroud)
每个都可以返回一个空值,默认值除外.每个功能可以采用不同的参数.例如,第一个可以不带参数,第二个可以接受一个字符串,第三个可以接受三个参数,等等.我想做的是:
ObjectUtils.firstNonNull(first(), second(), ..., default());
Run Code Online (Sandbox Code Playgroud)
问题在于,由于函数调用,这需要进行急切的评估.我想早点退出,在第二个函数之后说(因为函数调用可能很昂贵,想想API调用等).在其他语言中,您可以执行与此类似的操作:
return first() || second() || ... || default()
Run Code Online (Sandbox Code Playgroud)
在Java中,我知道我可以做类似的事情:
String value;
if (value = first()) == null || (value = second()) == null ...
return value;
Run Code Online (Sandbox Code Playgroud)
由于所有的== null检查,这不是非常易读的IMO.ObjectUtils.firstNonNull()首先创建一个集合,然后迭代,只要该函数被懒惰地评估,这是可以的.
建议?(除了做一堆ifs)
Rol*_*and 35
String s = Stream.<Supplier<String>>of(this::first, this::second /*, ... */)
.map(Supplier::get)
.filter(Objects::nonNull)
.findFirst()
.orElseGet(this::defaultOne);
Run Code Online (Sandbox Code Playgroud)
它在第一个非null值上停止,或者设置从中返回的值defaultOne.只要你保持顺序,你就是安全的.当然这需要Java 8或更高版本.
它在第一次出现非空值时停止的原因是Stream每个步骤处理的方式.这map是一个中间操作,也是filter.的findFirst另一侧是一个短路端子的操作.所以它继续下一个元素,直到一个匹配过滤器.如果没有元素匹配,则返回空的可选项,因此orElseGet调用-supplier.
this::first等等只是方法参考.如果它们是静电的,请用它YourClassName::first等替换它.
如果您的方法的签名不同,这是一个示例:
String s = Stream.<Supplier<String>>of(() -> first("takesOneArgument"),
() -> second("takes", 3, "arguments")
/*, ... */)
.map(Supplier::get)
.filter(Objects::nonNull)
.findFirst()
.orElseGet(this::defaultOne);
Run Code Online (Sandbox Code Playgroud)
请注意,Supplier仅在您呼叫时评估get.这样你就可以获得懒惰的评估行为.supplier-lambda-expression中的方法参数必须是最终的或有效的final.
这可以用干净的流完成Suppliers.
Optional<String> result = Stream.<Supplier<String>> of(
() -> first(),
() -> second(),
() -> third() )
.map( x -> x.get() )
.filter( s -> s != null)
.findFirst();
Run Code Online (Sandbox Code Playgroud)
这样做的原因在于,尽管有外观,但整个执行都是由findFirst()一个项目驱动的,它从filter()一个懒惰地拉出项目map(),从而调用get()处理每个拉动.findFirst()当一个项目通过过滤器时,将停止从流中拉出,因此后续供应商将不会get()调用.
虽然我个人觉得声明流风格更清洁,更表现,你不具备使用流与合作Supplier■如果你不喜欢的风格:
Optional<String> firstNonNull(List<Supplier<String>> suppliers {
for(Supplier<String> supplier : suppliers) {
String s = supplier.get();
if(s != null) {
return Optional.of(s);
}
}
return Optional.empty();
}
Run Code Online (Sandbox Code Playgroud)
显而易见的是,如果您从列表中耗尽选项,那么如果不返回,Optional您可以同样返回a String,返回null(yuk),默认字符串或抛出异常.
Rya*_*n S -3
您可以通过反射来完成此操作:
public Object getFirstNonNull(Object target, Method... methods) {
Object value = null;
for (Method m : methods) {
if ( (value = m.invoke(target)) != null) {
break;
}
}
return value;
}
Run Code Online (Sandbox Code Playgroud)