如何匹配流元素但如果不存在则返回false?

时间:2017-09-06 12:52:18

标签: java java-8 java-stream

我有一个流,想检查是否所有匹配过滤器。如果全部匹配,请返回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);
}

6 个答案:

答案 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()