Functional Operations vs For Loop – Why Should I Use Functional Operations Instead of a For Loop?

javajava8lambdastream-processing

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 forEach() 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?

Best Answer

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's 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.