我有一个流,想检查是否所有匹配过滤器。如果全部匹配,请返回true
。
但是,如果信息流为空,我想返回false
。
我该怎么做?
示例代码:
public boolean validate(Stream<Whatever> stream) {
// Problem: returns **true** if stream empty.
// How can **false** be returned if stream is empty?
return stream.allMatch(Whatever::someCheck);
}
答案 0 :(得分:16)
您可以使用
public boolean validate(Stream<Whatever> stream) {
return stream.map(Whatever::someCheck).reduce(Boolean::logicalAnd).orElse(false);
}
表达意图的。我们将每个元素映射到boolean
值,表示它是否匹配并使用逻辑和操作减少所有元素,如果所有元素都为true
,则会产生true
reduce
}。如果没有元素,Optional
将返回空false
,我们会按照预期使用orElse(false)
映射到public boolean validate(Stream<Whatever> stream) {
boolean parallel = stream.isParallel();
Spliterator<Whatever> sp = stream.spliterator();
if(sp.getExactSizeIfKnown() == 0) return false;
Stream.Builder<Whatever> b = Stream.builder();
if(!sp.tryAdvance(b)) return false;
return Stream.concat(b.build(), StreamSupport.stream(sp, parallel))
.allMatch(Whatever::someCheck);
}
。
唯一的缺点是这不是短路,即不会立即停在第一个非匹配元件上。
仍然支持短路的解决方案可能会进一步发展:
<comma><space>
这是Eugene’s answer的变体,但它不会失去特征或并行性,并且通常可能会更有效。
答案 1 :(得分:3)
以下代码可以使用(我测试过它)。
public static boolean validate(Stream<Whatever> stream) {
return stream.reduce((whatever1, whatever2) -> Whatever.someCheck(whatever1) ? whatever2 : whatever1)
.map(Whatever::someCheck).orElse(false);
}
它是如何工作的?我们使用reduce
操作来检查每个元素是否与谓词匹配,如果失败,我们将继续返回失败的元素(在三元操作中)。最后,我们将简化的Whatever
对象映射到布尔值,如果它是真的:那么所有匹配的并且这不是空的(orElse(false)
)。
答案 2 :(得分:2)
如果你可以失去你的特征和并行性,例如:
public static boolean validate(Stream<String> stream) {
Iterator<String> it = stream.iterator();
if (!it.hasNext()) {
return false;
}
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, 0), false)
.peek(System.out::println)
.allMatch(x -> x.contains("a"));
}
答案 3 :(得分:0)
尝试peek
boolean[] flag = new boolean[1];
return stream.peek(t -> flag[0] = true).allMatch(Whatever::someCheck) && flag[0]
答案 4 :(得分:0)
我已经添加了两个我现在删除的答案,但问题一直在唠叨我,所以我给了它第三次尝试,这次它的工作包括保持allMatch
。以下是方法validate
的代码。
public static boolean validate(Stream<Whatever> stream) {
final boolean[] streamNotEmpty = new boolean[1];
return stream.filter(elem -> {
streamNotEmpty[0] = true;
return true;
}).allMatch(Whatever::someCheck) && streamNotEmpty[0];
}
较短的版本是
public static boolean validate(Stream<Whatever> stream) {
final boolean[] streamNotEmpty = new boolean[1];
return stream.allMatch(elem -> {
streamNotEmpty[0] = true;
return elem.someCheck();
}) && streamNotEmpty[0];
}
这背后的想法是我们想要知道流中是否至少有一个元素,所以我创建了一个final boolean[]
,其中值在filter-call中被更改。因此,在流处理结束时,我们可以检查流是否为空,并在返回结果时采取相应的行动。
这是一个完整的类,包括测试用例来证明 - 最后这次 - 我提供了一个有效的解决方案。
import java.util.ArrayList;
import java.util.stream.Stream;
public class StreamTest {
public static boolean validate(Stream<Whatever> stream) {
final boolean[] streamNotEmpty = new boolean[1];
return stream.allMatch(elem -> {
streamNotEmpty[0] = true;
return elem.someCheck();
}) && streamNotEmpty[0];
}
static class Whatever {
private boolean checkResult;
public Whatever() {
this(false);
}
public Whatever(boolean b) {
this.checkResult = b;
}
public boolean someCheck() {
return checkResult;
}
}
public final static void main(String[] args) {
ArrayList<Whatever> list = new ArrayList<>();
System.out.println("empty list: " + validate(list.stream()));
System.out.println("empty list parallel: " + validate(list.parallelStream()));
for (int i = 0; i < 10000; i++) {
list.add(new Whatever(true));
}
System.out.println("non empty true list: " + validate(list.stream()));
System.out.println("non empty true list parallel: " + validate(list.parallelStream()));
for (int i = 0; i < 10000; i += 1000) {
list.add(new Whatever(false));
}
System.out.println("non empty false list: " + validate(list.stream()));
System.out.println("non empty false list parallel: " + validate(list.parallelStream()));
}
}
执行时的输出是:
empty list: false
empty list parallel: false
non empty true list: true
non empty true list parallel: true
non empty false list: false
non empty false list parallel: false
答案 5 :(得分:-2)
return !stream.filter(Whatever::someCheck).collect(Collectors.toList()).isEmpty()