我有一个开销很大的方法,我只想在流中必要的时候调用它。下面是一个例子:
public static Optional<MyObject> findTarget(String input, List<MyObject> myList) {
return Stream.concat(myList.stream(), expensive().stream()).filter(o -> o.hasName(input)).findFirst();
}
目标是基于input
值从myList
中找到目标MyObject
,但如果它不在myList
ONLY中,则它将调用expensive()
以返回更大的列表并从那里查找。
上面的示例没有这样做,因为Stream.concat
似乎在使用所有myList
之前就已经调用了expensive()
。
我能想到的一个丑陋的解决方案是分两步来做,例如:
return myList.stream().filter(o -> o.hasName(input)).findFirst().or(
() -> expensive().stream().filter(o -> o.hasName(input)).findFirst());
但之后我将不得不重复过滤器和其余的两次。
有没有更好的解决方案,甚至是一个单一的流行这样做?
3条答案
按热度按时间u2nhd7ah1#
您可以通过连接
Supplier<List<MyObject>>
而不是List<MyObject>
来延迟求值。试验:
输出:
或者,您可以执行以下操作:
uxhixvfz2#
是的,您提供的示例是正确的。
Stream.concat()
方法将在使用所有myList
之前调用expensive()
方法,因此它不会像您希望的那样高效。另一种解决方案是使用带有supplier函数的
Stream.concat()
方法,而不是使用流。supplier函数只有在第一个流耗尽时才会被调用,因此它只会在必要时调用开销大的方法。下面是一个示例:这样,filter方法在将
myList
流与昂贵流连接之前应用于myList
流,这意味着仅当在myList
流中未找到目标时才调用昂贵方法。另一种方法是使用
Stream.concat()
和一个标志来检查是否调用了开销大的方法。它与第一个类似,但更明确,可读性更强。
这两种解决方案都应该比您提供的初始示例更有效。
mi7gmzs63#
另一种可能更容易理解的替代方案是在单独的方法中提取流逻辑:
然后简单地调用两次