10

Suppose I have a stream of boolean values and the reduce operation that I am writing is || (OR). Can I write it in a way such that the evaluation of at least some of the elements is abandoned if a true value is encountered?

I am looking for some amount of optimization (perhaps if it is a parallel stream), not necessarily full optimization although the latter would be awesome.

Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
necromancer
  • 23,916
  • 22
  • 68
  • 115

1 Answers1

19

I suspect you want this type of construct.

// stop when any element evaluates to true
boolean any = stream.anyMatch(t -> t);

You can check this with peek

Stream.of(1, 2, 3, 4).peek(System.out::println).anyMatch(i -> i == 2);

prints

1
2

For a parallel example

AtomicInteger count = new AtomicInteger();
IntStream.range(0, 1000).parallel().peek(t -> count.incrementAndGet()).anyMatch(i -> i == 2);
System.out.println("count: " + count);

prints a number like

count: 223

The exact number varies.

For a referencePipeline, the anyMatch calls

@Override
public final boolean anyMatch(Predicate<? super P_OUT> predicate) {
    return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ANY));
}

which calls this

public static <T> TerminalOp<T, Boolean> makeRef(Predicate<? super T> predicate,
        MatchKind matchKind) {
    Objects.requireNonNull(predicate);
    Objects.requireNonNull(matchKind);
    class MatchSink extends BooleanTerminalSink<T> {
        MatchSink() {
            super(matchKind);
        }

        @Override
        public void accept(T t) {
            if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
                stop = true;
                value = matchKind.shortCircuitResult;
            }
        }
    }

    return new MatchOp<>(StreamShape.REFERENCE, matchKind, MatchSink::new);
}

where you can start to see the short circuiting code.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • +1 thanks. I am looking for how to implement constructs such as `anyMatch` (can't find the source code somehow in my Eclipse). – necromancer Aug 04 '14 at 07:53
  • 1
    @necromancer The source is there, but it's not easy to read, it's pretty convoluted. Even the simple `.count()` is way more complicated than you might imagine. I suggest trying to use the constructs already available to do what you want. – Peter Lawrey Aug 04 '14 at 07:59
  • 1
    Ahem, you can’t rely on `peek` for a parallel stream. At the time, `anyMatch` recognizes that there is a match, `peek` might have seen a lot of matches already. – Holger Aug 04 '14 at 08:33
  • 4
    @Holger I agree, which is why I got `223` on one run and "The exact number varies" I was relying on the fact that peek might show the stream was short circuited. – Peter Lawrey Aug 04 '14 at 08:37
  • why not use `findFirst` to ensure elements are visited in sequence? – njzk2 Apr 15 '21 at 20:34