Pawel Duda github twitter

Java 8 loops - not only collection processing

12 January 2015

Recently an interesting post by @mariushe has been making rounds on Twitter. In it the author emphasises the Java 8 feature of streams allowing for functional processing of collections as opposed to the traditional ‘for’ loop:

  articles.stream()
    .filter(article -> article.getTags().contains("Java"))
    .findFirst();

Java programmers indeed seem to like this feature. I have already seen quite a number of great posts, articles and presentations about it.

But what about ordinary integer-based loops?

Now, it might be just me but I have only come across one post that mentions ordinary integer-based loops like: Java 7 and older:

for (int i = 0; i < 10; i++) {
  System.out.println(i);
}

Which can be replaced in Java 8 with IntStream:

  IntStream.range(0, 10).forEach(
    nbr -> System.out.println(nbr)
  );
}

Adam Bien explains it makes it really easy to declaratively enable parallel processing. As indicated by Adam the following snippet takes 1 second and not 10 seconds:

  IntStream.range(0, 10).parallel().forEach( nbr -> {
    try {
      Thread.sleep(1000);
    } catch (InterruptedException ex) {
      // swallow it
    }
    System.out.println(nbr);
  });

In my opinion IntStream loops are possibly also easier to read (probably a matter of taste). I have never gotten 100% comfortable with the fact an idiomatic Java 7 loop from 1 to 10 actually starts with 0 (and not 1) but ends with 10 (as long as my team members and I remember to consistently use the ‘less than’ operator):

for (int i = 0; i < 10; i++) {
  // adding 1 because loops idiomatically start with 0 and use the 'less than' operator
  System.out.println(i + 1);
}

In Java 8 I have two methods that help out:

  // rangeClosed method
  IntStream.rangeClosed(1, 10).forEach(
    nbr -> System.out.println(nbr) // gets printed 10 times (1-10)
  );

  // range method (makes it easy to migrate idiomatic Java 7 loops to IntStream loops)
  IntStream.range(0, 10).forEach(
    nbr -> System.out.println(nbr) // gets printed 10 times (0-9)
  );
}

So with ‘rangeClosed’ there are no comparisons. Nice and clean declarative statement.

Ruby digression

But maybe I am a little biased by Ruby. Avdi Grimm in his screencast Ruby Tapas #173 explains that the counterpart of IntStream in the Ruby world, the ‘each’ method, is the idiomatic way of looping:

fruits = ['apple', 'banana']
fruits.each do |fruit|
  puts "I love #{fruit}"
end

(1..10).each do |n|
  puts "I am #{n} years old"
end

Although the ‘for’ syntax exists:

fruits = ['apple', 'banana']
for fruit in fruits
  puts "I love #{fruit}"
end
for n in 1..10
  puts "I am #{n} years old"
end

… under the hood it is actually syntactic sugar and it gets translated into an ‘each’ method invokation. ‘For’ in the sense obscures what is really going on, that is that the object we are iterating on has to respond to the ‘each’ method.

More importantly though, apart from the syntactic difference, the ‘each’ loop in Ruby creates a new variable scope. This means it effectively removes the risk of mutating an existing variable, if used as the loop counter.

Summary

But enough about Ruby. I am simply wondering how successful the new Java 8 syntax will be in replacing the old habits of Java programmers… I am guessing this will be the case for collections processing. Again, I see a lot written on that. But I suppose the strongest habit, ‘for’ loops for plain old integer-based loops might stay on. Just a guess… We will see :)

Which syntax do you prefer?