4

If I have a List containing objects like

new MyObj("some"),
new MyObj("foo"),
new MyObj("bar"),
new MyObj("xyz");

and want to filter it with Java 8 streams after match some condition, say

myObj.prop = "foo";

how would that be accomplished?

The result of the above example should be

new MyObj("some"),
new MyObj("foo")

That would be the "traditional" way:

List<MyObj> results = new ArrayList<>();
for (MyObj myObj : myObjList) {
  if (!myObj.prop.equals("foo")) {
    results.add(myObj);
  } else {
    results.add(myObj);
    break;
  }
}

It is not exaclty a duplicate of Limit a stream by a predicate because that does not include the matched element. However, I should be able to adapt the takeWhile operation.

Zaki
  • 6,997
  • 6
  • 37
  • 53
saimonsez
  • 344
  • 3
  • 16

1 Answers1

5

Unfortunately such scenario is not directly supported by Stream API. Even takeWhile, which is newly appeared method in Java 9 would not solve this. Some free third-party Stream API extensions have a method you need. For example, limitWhileClosed in jOOλ or takeWhileInclusive in StreamEx (the library I wrote). Here's an example, how to do it via StreamEx:

List<MyObj> results = StreamEx.of(myObjList)
    .takeWhileInclusive(myObj -> !myObj.prop.equals("foo")).toList();

jOOλ version would look pretty similar.

Without using third-party libraries you can solve this in two passes:

int idx = IntStream.range(0, myObjList.size())
         .filter(i -> myObjList.get(i).prop.equals("foo"))
         .findFirst().orElse(myObjList.size());

List<MyObj> results = myObjList.stream().limit(idx+1).collect(Collectors.toList());
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
  • 2
    …or `results = idx==myObjList.size()? myObjList: myObjList.subList(0, idx+1);`, depending on the use case. – Holger Feb 17 '17 at 09:37