- 对于提供的输入
[1,2,3,4,5,10,12,30,40,50],预期的输出[1,2,3,4,5,10]应该由简单的过滤器返回:
static List<Integer> findBelow(List<Integer> inputList, Predicate<Integer> condition) {
return inputList.stream()
.filter(condition::test)
.collect(Collectors.toList());
}
- 如果需要指定索引范围,应该使用
IntStream::range实现:
static List<Integer> findBelow(List<Integer> inputList, int start, int end, Predicate<Integer> condition) {
start = Math.max(0, start);
end = Math.min(inputList.size(), end);
return IntStream.range(start, end)
.filter(i -> condition.test(inputList.get(i)))
.mapToObj(inputList::get)
.collect(Collectors.toList());
}
显然,这些实现不会 break 退出循环,Java 8 Stream API 没有相应的功能。
可以提供以下解决方法:
- 使用
findFirst检测第一个不匹配的索引,然后限制索引的范围:
static List<Integer> findWithFirst(List<Integer> inputList, int start, int end, Predicate<Integer> condition) {
start = Math.max(0, start);
end = Math.min(inputList.size(), end);
int firstNonMatch = IntStream.range(start, end)
.filter(i -> !condition.test(inputList.get(i)))
.findFirst()
.orElse(maxSize);
return IntStream.range(start, firstNonMatch) // no filter needed any longer
.mapToObj(inputList::get)
.collect(Collectors.toList());
}
- 在过滤输入列表时使用流外部的布尔标志检查是否满足倒置的
break 条件:
// using AtomicBoolean
static List<Integer> findAndBreak2(List<Integer> inputList, int start, int end, Predicate<Integer> condition) {
AtomicBoolean breakFound = new AtomicBoolean(false);
return IntStream.range(start, Math.min(inputList.size(), end))
.filter(i -> {
breakFound.set(
breakFound.get() || !condition.test(inputList.get(i))
);
return !breakFound.get();
})
.mapToObj(inputList::get)
.collect(Collectors.toList());
}
// using static class field
static boolean found = false;
static List<Integer> findAndBreak(List<Integer> inputList, int start, int end, Predicate<Integer> condition) {
found = false;
return IntStream.range(start, Math.min(inputList.size(), end))
.filter(i -> { found |= !condition.test(inputList.get(i)); return !found; })
.mapToObj(inputList::get)
.collect(Collectors.toList());
}
测试:
条件i <= 10 是微不足道的,因为它适用于所有情况。
反转条件i > 10,如 OP 代码所示,break 生成空列表。
Predicate<Integer> condition = (i) -> i > 10;
List<Integer> inputList = Arrays.asList(1,2,3,4,5,10,12,30,40,50);
List<Integer> finalResult = new ArrayList<>();
int index = 0, maxSize = 10;
while (index < maxSize) {
if (condition.test(inputList.get(index))) {
finalResult.add(inputList.get(index));
} else {
break;
}
index++;
}
System.out.println("loop: " + finalResult);
System.out.println("plain filter: " + findBelow(inputList, condition));
System.out.println("filter and range limit: " + findBelow(inputList, 0, maxSize, condition));
System.out.println("filter and break static: " + findAndBreak(inputList, 0, maxSize, condition));
System.out.println("filter and break atomic: " + findAndBreak2(inputList, 0, maxSize, condition));
System.out.println("filter and findFirst: " + findWithFirst(inputList, 0, maxSize, condition));
输出:
loop: []
plain filter: [12, 30, 40, 50]
filter and range limit: [12, 30, 40, 50]
filter and break static: []
filter and break atomic: []
filter and findFirst: []