0

I have a Java 8 stream of objects and I would like to ignore the objects after a given predicate is matched.

Example : I would like to keep all the strings up-to the "BREAK" one (and including it).

public List<String> values = Arrays.asList("some", "words", "before", "BREAK", "AFTER");

@Test
public void testStopAfter() {
    Stream<String> stream = values.stream();
    //how to filter stream to stop at the first BREAK
    //stream = stream.filter(s -> "BREAK".equals(s));
    final List<String> actual = stream.collect(Collectors.toList());

    final List<String> expected = Arrays.asList("some", "words", "before", "BREAK");
    assertEquals(expected, actual);
}

As it is it fails (expected:<[some, words, before, BREAK]> but was:<[some, words, before, BREAK, AFTER]>), and if I uncomment the filter, I only get the "BREAK"

I am thinking of a statefull Predicate (see my answer below) but I was wandering if there was a nicer solution ?

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
Benoît
  • 1,080
  • 11
  • 28
  • Substream or something of that sort? – awksp Oct 05 '15 at 16:55
  • Looks like you want a substream from your original stream. – Luiggi Mendoza Oct 05 '15 at 16:56
  • @LuiggiMendoza Yes a substream would be perfectly fine – Benoît Oct 05 '15 at 16:57
  • @LouisWasserman thanks for the link to your answer. I had not found it (bad search keywords). It is not a exact answer as I need to keep the BREAK (the first matching the predicate) in the output, but your code can be adapted. Thanks. – Benoît Oct 05 '15 at 19:02
  • 1
    @Benoît, actually the duplicate link was wrong. I updated it to the question which asks about your exact problem. – Tagir Valeev Oct 06 '15 at 01:53
  • @TagirValeev thanks : your duplicate link is an exact match to my question. But I like Louis's `SplitIterator` [implementation](http://stackoverflow.com/a/20765715/4462333) and I adapted his answer to these requirements. I've added it as another [answer](http://stackoverflow.com/a/32964743/4462333) to the linked question. – Benoît Oct 06 '15 at 08:07

1 Answers1

0

Using a statefull Predicate that answer true before and false after the given Predicate matches.

[...]
stream = stream.filter(makeUntil(s -> "BREAK".equals(s)));
[...]


public static <T> Predicate<T> makeUntil(final Predicate<T> predicate) {
    return new Predicate<T>() {

        private boolean hasMatched;

        @Override
        public boolean test(final T s) {
            if (hasMatched) {
                return false;
            }
            else {
                hasMatched = predicate.test(s);
                return true;
            }
        }

    };
}
Benoît
  • 1,080
  • 11
  • 28