Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top
    for (Canvas canvas : list) {

    }

NetBeans suggests me to use "functional operations":

    list.stream().forEach((canvas) -> {

    });

But why is this preferred? If anything, it is harder to read and understand. You are calling stream(), then foreEach(), then using a lambda expression with parameter canvas. I don't see how is that any nicer than the for loop in the first snippet.

Obviously I am speaking out of aesthetics only. Perhaps there is a technical advantage here that I am missing. What is it? Why should I use the second method instead?

share|improve this question
2  
12  
In your particular example, it would not be preferred. – Robert Harvey Sep 13 '15 at 20:42
    
As long as the only operation is a single forEach, I tend to agree with you. As soon as you add other operations to the pipeline, or you produce an output sequence, then the stream-approach becomes preferable. – JacquesB Dec 1 '15 at 21:56
up vote 23 down vote accepted

Streams provide much better abstraction for composition of different operations you want to do on top of collections or streams of data coming in. Especially when you need to map elements, filter and convert them.

Your example is not very practical. Consider the following code from Oracle site.

List<Transaction> groceryTransactions = new Arraylist<>();
for(Transaction t: transactions){
  if(t.getType() == Transaction.GROCERY){
    groceryTransactions.add(t);
  }
}
Collections.sort(groceryTransactions, new Comparator(){
  public int compare(Transaction t1, Transaction t2){
    return t2.getValue().compareTo(t1.getValue());
  }
});
List<Integer> transactionIds = new ArrayList<>();
for(Transaction t: groceryTransactions){
  transactionsIds.add(t.getId());
}

can be written using streams:

List<Integer> transactionsIds = 
    transactions.stream()
                .filter(t -> t.getType() == Transaction.GROCERY)
                .sorted(comparing(Transaction::getValue).reversed())
                .map(Transaction::getId)
                .collect(toList());

The second option is much more readable. So when you have nested loops or various loops doing partial processing, it's very good candidate for Streams/Lambda API usage.

share|improve this answer
4  
There are optimization techniques like map fusion (stream.map(f).map(g)stream.map(f.andThen(g))) build/reduce fusion (when building a stream in one method and then passing it to another method which consumes it, the compiler can eliminate the stream) and stream fusion (which can fuse many stream ops together into a single imperative loop), which can make stream operations much more efficient. They are implemented in the GHC Haskell compiler, and also in some other Haskell and other functional language compilers, and there are experimental research implementations for Scala. – Jörg W Mittag Sep 14 '15 at 3:05
    
@lkrnac, thanks for the heads up. I've deleted my comment. – David Arno Sep 14 '15 at 9:29

If anything, it is harder to read and understand.

That is highly subjective. I find the second version much easier to read and understand. It matches how other languages (e.g. Ruby, Smalltalk, Clojure, Io, Ioke, Seph) do it, it requires fewer concepts to understand (it's just a normal method call like any other, whereas the first example is specialized syntax).

If anything, it's a matter of familiarity.

share|improve this answer
4  
Yeah that's true. But this looks more like a comment than an answer to me. – Omega Sep 14 '15 at 3:25

Another advantage of using the functional streaming API is, that it hides implementation details. It only describes what should be done, not how. This advantage becomes obvious when looking at the change that needs to be done, to change from single threaded to parallel code execution. Just change the .stream() to .parallelStream().

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.