Por que devo usar “operações funcionais” em vez de um loop for?

38
for (Canvas canvas : list) {
}

O NetBeans sugere que eu use "operações funcionais":

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

Mas por que isso é preferido ? Se alguma coisa, é mais difícil de ler e entender. Você está chamando stream() e, em seguida, forEach() usando uma expressão lambda com o parâmetro canvas . Eu não vejo como isso é melhor do que o loop for no primeiro snippet.

Obviamente, estou falando apenas de estética. Talvez haja uma vantagem técnica aqui que estou perdendo. O que é isso? Por que devo usar o segundo método?

    
por Omega 13.09.2015 / 21:12
fonte

3 respostas

44

Os fluxos fornecem uma abstração muito melhor para a composição de diferentes operações que você deseja fazer além das coleções ou fluxos de dados que chegam. Especialmente quando você precisa mapear elementos, filtrá-los e convertê-los.

Seu exemplo não é muito prático. Considere o seguinte código do site da Oracle .

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());
}

pode ser escrito usando streams:

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

A segunda opção é muito mais legível. Então, quando você tem loops aninhados ou vários loops fazendo processamento parcial, é muito bom candidato para o uso da API do Streams / Lambda.

    
por 13.09.2015 / 21:24
fonte
16

Outra vantagem de usar a API de streaming funcional é que ela oculta detalhes de implementação. Descreve apenas o que deve ser feito, não como. Esta vantagem torna-se óbvia quando se olha para a mudança que precisa ser feita, para mudar de uma única execução de código para execução paralela. Basta alterar o .stream() para .parallelStream() .

    
por 14.09.2015 / 00:11
fonte
13

If anything, it is harder to read and understand.

Isso é altamente subjetivo. Acho a segunda versão muito mais fácil de ler e entender. Ele combina com outras linguagens (por exemplo, Ruby, Smalltalk, Clojure, Io, Ioke, Seph), requer menos conceitos para entender (é apenas uma chamada de método normal como qualquer outra, enquanto o primeiro exemplo é sintaxe especializada).

Se qualquer coisa, é uma questão de familiaridade.

    
por 14.09.2015 / 05:17
fonte