我有以下流代码:
List<Data> results = items.stream()
.map(item -> requestDataForItem(item))
.filter(data -> data.isValid())
.collect(Collectors.toList());
Data requestDataForItem(Item item) {
// call another service here
}
问题是我想打电话
仅当流中的所有元素都有效时才requestDataForItem
。
例如,
如果第一项无效,我不会调用流中的任何元素。
流API中有.allMatch
,
但它返回boolean
。
我想和.allMatch
做同样的事情
.collect
当一切都匹配时的结果。
另外,我想只处理一次流,
有两个循环很容易。
这是否可以使用Java Streams API?
答案 0 :(得分:3)
这将是Java 9的一项工作:
List<Data> results = items.stream()
.map(item -> requestDataForItem(item))
.takeWhile(data -> data.isValid())
.collect(Collectors.toList());
此操作将在第一个无效元素处停止。在顺序执行中,这意味着不会进行后续的requestDataForItem
调用。在并行执行中,一些额外的元素可能会在操作停止之前同时处理,但这是高效并行处理的代价。
在任何一种情况下,结果列表只包含第一个遇到无效元素之前的元素,您可以使用results.size() == items.size()
轻松检查所有元素是否有效。
在Java 8中,没有这样简单的方法,并且使用额外的库或推出自己的takeWhile
实现将无法考虑非流解决方案的简单性
List<Data> results = new ArrayList<>();
for(Item item: items) {
Data data = requestDataForItem(item);
if(!data.isValid()) break;
results.add(data);
}
答案 1 :(得分:1)
实施两步流程:
答案 2 :(得分:1)
理论上你可以使用.allMatch
然后收集如果.allMatch
返回true,但是那么你将处理该集合两次。你无法直接使用流API进行操作。
您可以创建一个方法来为您执行此操作,只需将您的集合传递给它,而不是使用流API。这比使用流API稍微不那么优雅,但是因为它只处理集合一次效率更高。
List<Data> results = getAllIfValid(
items.stream().map(item ->
requestDataForItem(item).collect(Collectors.toList())
);
public List<Data> getAllIfValid(List<Data> items) {
List<Data> results = new ArrayList<>();
for (Data d : items) {
if (!d.isValid()) {
return new ArrayList<>();
}
results.add(d);
}
return results;
}
如果每个元素都通过,它将返回所有结果,并且只处理items
集合一次。如果isValid()
检查失败,它将返回一个空列表,因为你想要全部或全部。只需检查返回的集合是否为空,以查看是否所有项目都通过了isValid()
检查。
答案 3 :(得分:0)
试试这个。
List<Data> result = new ArrayList<>();
boolean allValid = items.stream()
.map(item -> requestDataForItem(item))
.allMatch(data -> data.isValid() && result.add(data));
if (!allValid)
result.clear();