47

I have this code:

List<String> strings = Arrays.asList("a", "b", "cc");
for (String s : strings) {
    if (s.length() == 2)
        System.out.println(s);
}

I want to write it using a filter and a lambda:

for (String s : strings.stream().filter(s->s.length() == 2)) {
    System.out.println(s);
}

I get Can only iterate over an array or an instance of java.lang.Iterable.

I try:

for (String s : strings.stream().filter(s->s.length() == 2).iterator()) {
    System.out.println(s);
}

And I get the same error. Is this even possible? I would really prefer not to do stream.forEach() and pass a consumer.

Edit: it's important to me not to copy the elements.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
ytoledano
  • 3,003
  • 2
  • 24
  • 39
  • 4
    If you use a `Stream`, why iterate in the first place? Note: your code can be written `strings.stream().filter(s -> s.length() == 2).forEach(System.out::println)` – fge Jun 25 '15 at 07:38
  • I actually have a big chunk of code processing the element and I don't want to refactor it too much if possible – ytoledano Jun 25 '15 at 07:39
  • 2
    Then just don't refactor if it works. Using streams for the sake of using streams is not the way to use streams :p – fge Jun 25 '15 at 07:39
  • 2
    You'll have to excuse my C#... there you wouldn't think twice about changing a `if (...) continue` to a `.where(!...)` on the IEnumerable – ytoledano Jun 25 '15 at 07:42
  • 2
    The answer to this question is given in an [answer](http://stackoverflow.com/a/20130475/452775) to the question which @TagirValeev links to. – Lii Jun 25 '15 at 07:44
  • 1
    @fge `forEachOrdered` might be more appropriate... – glglgl Dec 13 '15 at 17:15
  • See [How do I iterate over a stream in Java using for? #2](http://stackoverflow.com/a/41046064/1421194). – Sasha Dec 08 '16 at 19:57
  • @fge because forEach is clumsy and not very readable for anything other than very simple expressions. – sfkleach Feb 14 '19 at 17:09
  • You can convert a `myStream` into `Iterable` as follows `for (X x : (Iterable)myStream::iterator) { // do something }`. This is helpful when you want to avoid creating an array object. – Oleg Afanasyev May 21 '21 at 10:35

1 Answers1

46

You need an iterable to be able to use a for-each loop, for example a collection or an array:

for (String s : strings.stream().filter(s->s.length() == 2).toArray(String[]::new)) {

Alternatively, you could completely get rid of the for loop:

strings.stream().filter(s->s.length() == 2).forEach(System.out::println);

You mention you don't want to refactor your for loop but you could extract its body in another method:

strings.stream().filter(s->s.length() == 2).forEach(this::process);

private void process(String s) {
  //body of the for loop
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 4
    Does toArray() copy the elements? I forgot to mention this in the orig question but I'd really prefer not to copy. – ytoledano Jun 25 '15 at 07:40
  • 1
    @ytoledano yes it would create a new array and copy the element references into the array. – assylias Jun 25 '15 at 07:41
  • 1
    Thanks, I'm keeping it as it is. – ytoledano Jun 25 '15 at 07:43
  • @ytoledano You did not give details on the content of the for loop body - there may be better ways depending on what it is... – assylias Jun 25 '15 at 07:45
  • 12
    @assylias, when refactoring the old code there can be many various things which prevent you from using lambdas like mutable variables or checked exceptions. This can be considered as bad design from the Java-8 point of view, but it's still the code which works and should be supported. Refactoring everything at once might be problematic. I personally saw many `for` loops which may benefit from stream API, but cannot be easily converted to `forEach/collect`. Also note that `for` loop is much easier to debug compared to lambda. – Tagir Valeev Jun 25 '15 at 07:52
  • 3
    @TagirValeev certainly - and there are cases where for loops are just easier and more readable. I'm just saying that without knowing what is inside the loop it's difficult to say if streams are a good fit or not. – assylias Jun 25 '15 at 08:16
  • Pros and cons of both loop styles: http://stackoverflow.com/questions/16635398/java-8-iterable-foreach-vs-foreach-loop – Vadzim Jul 29 '15 at 16:13
  • Above code will not work In case of static context - "Cannot use this in a static context" – PAA Aug 16 '16 at 19:55