流已经被操作或关闭
stream has already been operated upon or closed
方法是
private List<HighWay> getWillSave(List<HighWay> total,
HighWayRepository repository) {
List<HighWay> willSave = new ArrayList<HighWay>();
int lastSaved = total.size() - 1;
while (lastSaved >= 0
&& repository.exists(total.get(lastSaved).getId())) {
lastSaved--;
}
willSave.addAll(total.subList(0, ++lastSaved));
return willSave;
}
现在想改成这样,不知道改对不对:
private List<HighWay> getWillSave(Stream<HighWay> notDealItem,
HighWayRepository repository) {
List<HighWay> willSave = new ArrayList<HighWay>();
long lastSaved = notDealItem.count()-1;
while (lastSaved >= 0
&& repository.exists(notDealItem.skip(lastSaved-1).findFirst().get().getId())) {
lastSaved--;
}
willSave.addAll(notDealItem.collect(Collectors.toList()).subList(0, (int)(++lastSaved)));
return willSave;
}
但是抛出异常:
java.lang.IllegalStateException: stream has already been operated upon
or closed
我知道流只能消费一次。而count和get方法都是consumer方式。但我真的很想知道计数并调用get方法。
如何避免异常和解决问题?
我应该以某种方式重构代码吗?
好吧,我想你可以做类似的事情......但与我们用 真正的 函数式语言可以做的相比,它非常不优雅:
private List<HighWay> getWillSave(List<HighWay> total, HighWayRepository repository) {
List<HighWay> willSave = new ArrayList<HighWay>();
int size = total.size();
int index =
IntStream.range(0,size)
.mapToObj(i -> new Pair<>(i,size - i - 1))
.filter(p -> !repository.exists(p.getValue().getId()))
.findFirst()
.orElseGet(() -> new Pair<>(0,null)).getKey();
return total.subList(0,index);
}
如果我理解您的代码逻辑,您想要 return list/stream 中的所有项目,直到您处于剩余未通过测试的点 repository.exists
。那是对的吗?如果是这样,那么可以使用自定义收集器来实现:
class MyCollector {
private List<Highway> acceptedList = new ArrayList<>();
private List<Highway> currentList = new ArrayList<>();
public void accept(Highway highway) {
if (repostitory.exists(highway.getId())) {
acceptedList.addAll(currentList);
acceptedList.add(highway);
currentList.clear();
} else {
currentList.add(highway);
}
}
public Stream<Highway> stream() {
return acceptedList.stream();
}
}
我希望清楚它是如何工作的:如果项目未通过测试,它们将被放入临时列表,直到找到通过的项目。对于最后一系列失败的项目,它们永远不会放回最终列表中。为了简单起见,我跳过了组合器。
然后可以将其应用于您的高速公路流,如下所示:
highwayStream()
.collect(MyCollector::new, MyCollector::accept, null)
.stream()
然后你可以做任何你想做的事,包括 .collect(Collectors.toList())
如果你真的需要 return 一个 List
而不是另一个流。
在提供了这个解决方案之后,我要说的是,我不相信流应该用于所有目的。它们最适合对项目进行相当独立操作的情况。在你的情况下,最终列表非常依赖于其他项目。
更直接的解决方案可能是:
List<Highway> filteredList = new ArrayList(originalList);
int i = filteredList.size() - 1;
while (i >= 0 && repository.exists(filteredList.get(i).getId()))
filteredList.remove(i--);
return filteredList;
方法是
private List<HighWay> getWillSave(List<HighWay> total,
HighWayRepository repository) {
List<HighWay> willSave = new ArrayList<HighWay>();
int lastSaved = total.size() - 1;
while (lastSaved >= 0
&& repository.exists(total.get(lastSaved).getId())) {
lastSaved--;
}
willSave.addAll(total.subList(0, ++lastSaved));
return willSave;
}
现在想改成这样,不知道改对不对:
private List<HighWay> getWillSave(Stream<HighWay> notDealItem,
HighWayRepository repository) {
List<HighWay> willSave = new ArrayList<HighWay>();
long lastSaved = notDealItem.count()-1;
while (lastSaved >= 0
&& repository.exists(notDealItem.skip(lastSaved-1).findFirst().get().getId())) {
lastSaved--;
}
willSave.addAll(notDealItem.collect(Collectors.toList()).subList(0, (int)(++lastSaved)));
return willSave;
}
但是抛出异常:
java.lang.IllegalStateException: stream has already been operated upon or closed
我知道流只能消费一次。而count和get方法都是consumer方式。但我真的很想知道计数并调用get方法。
如何避免异常和解决问题?
我应该以某种方式重构代码吗?
好吧,我想你可以做类似的事情......但与我们用 真正的 函数式语言可以做的相比,它非常不优雅:
private List<HighWay> getWillSave(List<HighWay> total, HighWayRepository repository) {
List<HighWay> willSave = new ArrayList<HighWay>();
int size = total.size();
int index =
IntStream.range(0,size)
.mapToObj(i -> new Pair<>(i,size - i - 1))
.filter(p -> !repository.exists(p.getValue().getId()))
.findFirst()
.orElseGet(() -> new Pair<>(0,null)).getKey();
return total.subList(0,index);
}
如果我理解您的代码逻辑,您想要 return list/stream 中的所有项目,直到您处于剩余未通过测试的点 repository.exists
。那是对的吗?如果是这样,那么可以使用自定义收集器来实现:
class MyCollector {
private List<Highway> acceptedList = new ArrayList<>();
private List<Highway> currentList = new ArrayList<>();
public void accept(Highway highway) {
if (repostitory.exists(highway.getId())) {
acceptedList.addAll(currentList);
acceptedList.add(highway);
currentList.clear();
} else {
currentList.add(highway);
}
}
public Stream<Highway> stream() {
return acceptedList.stream();
}
}
我希望清楚它是如何工作的:如果项目未通过测试,它们将被放入临时列表,直到找到通过的项目。对于最后一系列失败的项目,它们永远不会放回最终列表中。为了简单起见,我跳过了组合器。
然后可以将其应用于您的高速公路流,如下所示:
highwayStream()
.collect(MyCollector::new, MyCollector::accept, null)
.stream()
然后你可以做任何你想做的事,包括 .collect(Collectors.toList())
如果你真的需要 return 一个 List
而不是另一个流。
在提供了这个解决方案之后,我要说的是,我不相信流应该用于所有目的。它们最适合对项目进行相当独立操作的情况。在你的情况下,最终列表非常依赖于其他项目。
更直接的解决方案可能是:
List<Highway> filteredList = new ArrayList(originalList);
int i = filteredList.size() - 1;
while (i >= 0 && repository.exists(filteredList.get(i).getId()))
filteredList.remove(i--);
return filteredList;