Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
August 15, 2022 11:38 am GMT

[PT-BR] Collections, forEach, Lambda Expressions - o que so external ou internal iterators?

muito comum utilizarmos estruturas de dados para nos ajudar a atender as necessidades requeridas em nossas aplicaes. Uma dessas estruturas so as collections. Elas so to comuns que remover at mesmo uma pequena quantidade de cerimnia para oper-las traria um grande ganho na reduo de possveis confuses que podem aparecer em nossos cdigos.

Vamos explorar como podemos utilizar as Lambda Expressions para manipular essas tais colees. Com elas podemos, de uma forma declarativa, filtrar dados, realizar transformaes, criar novas colees, concatenar elementos, entre outras operaes.

Iterando em Colees

Iterar por meio de uma lista uma operao bsica nas colees (collection), e ao longo dos anos, essa operao tambm sofreu mudanas significativa dentro da linguagem Java.

Vamos comear com um exemplo - enumerando uma lista de nomes - utilizando uma abordagem mais antiga e seguir evoluindo at uma verso onde a escrita dessa operao apresente uma forma mais concisa e elegante.

Aqui criamos uma coleo imutvel de lista de nomes:

  final List<String> developers = List.of(              "Maximillian",              "Otavio Santana",              "Bruno Souza",              "Elder Moraes",              "Srgio Lopes",              "Fernando Boaglio");

Abaixo, uma forma de iterar e escrever cada item no console:

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

Provavelmente, alguma vez, durande a escrita de um lao for conforme escrito acima, vc se deparou questionando: i < ou i <=. Essa abordagem bem verbosa e propensa a erros, e outra, ela s til se precisarmos manipular elementos em um particular ndice na coleo.

Uma outra forma que o Java tambm oferece do que o bom e velho for:

    for (String developer: developers) {        System.out.println(developer);    }

Por baixo do cap, essa forma utiliza a interface Iterator para iterar entre os itens, chamando o mtodo hasNext para saber quando parar de iterar, e o mtodo next para capturar o item na posio corrente.

Nesses dois casos, so utilizados iteradores externos (external iterators 1).

No primeiro exemplo, precisamos explicitamente controlar a iterao, indicando onde comear e onde parar; J no segundo, essas mesmas operaes acontecem por baixo dos panos utilizando os mtodos da interface Iterator. E mais, atravs desse controle explcito, podemos utilizar as declaraes break e continue para gerenciar o fluxo de controle da execuo da iterao.

Com external iterators, instruimos o programa COMO fazer a iterao para que, s ento atingir o QUE queremos no final das contas.

J no segundo exemplo, iteramos entre os elementos da coleo com menos cerimnia do que a primeira verso. Essa estrutura s melhor do que a primeira quando no temos a inteno de acessar ou modificar a coleo baseada em ndices e posies especficas , porm, ambas utilizam um estilo imperativo e ns podemos dispensar essa abordagem uma vez que podemos utilizar o estilo funcional.

H boas razes a favor de mudar do estilo imperativo para o estilo funcional:

  • Loops utilizando for so inerentemente sequenciais e so difceis de paralelizar;
  • Tais loops so non-polymorphic, isto , temos que passar a coleo na instruo do for ao invs de executar algum mtodo (que pode usufruir do polimorfismo por baixo dos panos) na coleo para executar a tarefa.
  • No nvel de design, o princpio "Tell, don't ask"2 cai por terra! Ns solicitamos a execuo de uma especfica iterao ao invs de deixar esses detalhes da iterao para a biblioteca de nvel mais baixo.

Dito isso, vamos utilizar o estilo funcional no lugar do imperativo, e assim utilizar iteradores internos (internal iterators 1).

Com uma internal iterators, ns deixamos a maioria das instrues de COMO fazer tal iterao para a biblioteca de nvel mais baixo e focamos no QUE queremos realizar durante a iterao.

A interface Iterable foi melhorada no Java 8 com um mtodo especial chamado forEach, que aceita um parmetro do tipo Consumer. Como o prprio nome indica, uma instncia do tipo Consumer ir consumir o que for passado pra ele atravs do seu mtodo accept.

  developers.forEach(new Consumer<String>() {      @Override      public void accept(final String developer) {          System.out.println(developer);      }  });

Ao trocar a utilizao do velho for pelo novo internal iterator 1 forEach ganhamos o benefcio de no necessitar focar em como iterar na coleo em questo e sim em no que fazer a cada iterao. O cdigo aplica o princpio Tell, don't ask de maneira satisfatria.

Espere um pouco, essa interface Consumer no uma interface funcional!

Exato! Com isso podemos utilizar Lambda Expressions ao invs de implementar uma classe annima!

O mtodo forEach um mtodo que aplica o pilar higher-order function, onde nos permite oferecer uma Lambda Expression ou um bloco de cdigo que ir executar dentro do contexto de cada elemento da lista. A varivel developer ser vinculada a cada elemento da coleo durante sua chamada.

Assim, a implementao por baixo dos panos deste mtodo ter o controle de como iterar e como executar o objeto de funo recebido como argumento. Encapsular a implementao atrs de mtodos como esse permitem que implementaes como essas possam tambm poder decidir vrios aspectos interessantes, como se a execuo deve ser ou no preguiosa (lazy), ou definir a ordem dos itens durante a iterao, ou at explorar o paralelismo como achar melhor. Esse o poder do encapsulamento.

  developers.forEach((final String developer) ->                             System.out.println(developer));

A sintaxe padro de Lambda Expressions espera que os parmetros estejam junto com seu tipo definido entre parnteses e separado por vrgulas, mas o compilador Java tambm oferece a inferncia de tipos 3 4 5.

Baseado na assinatura do mtodo da interface que a Lambda Expression est implementando, o compilador capaz de detectar qual o tipo do parmetro em questo e efetuar sua inferncia.

Vamos usufruir da inferncia de tipos em nosso exemplo tirando a declarao:

  developers.forEach((developer) ->                             System.out.println(developer));

Assim, baseado no contexto do mtodo, o compilador sabe determinar o tipo do parmetro que est sendo fornecido.

Para casos onde h multiplos parmetros, podemos seguir o mesmo princpio, no declarar o tipo de cada parmetro, mas se precisarmos especificar o tipo de um parmetro, precisaremos especificar o tipo de todos os parmentros, isto , ou declara nenhum ou declara todos os tipos de cada parmetros.

Para casos onde s h um parmetro, o compilador Java no exige que o parmetro esteja dentro de parenteses.

  developers.forEach(developer ->                             System.out.println(developer));

Mas uma resalva: parmetros inferidos so non-final. Em um dos exemplos anteriores, escrevemos uma Lambda Expression onde alm de explicitamente definir o tipo do parmetro, ns tambm definimos que o parmetro deve ser final. Isso instrui o compilador a nos alertar caso o parmetro for modificado dentro da Lambda Expression. De modo geral, modificar parmetros algo ruim que pode conduzir a erros, ento defini-los com final uma boa prtica.

Infelizmente, quando favorecemos a inferncia de tipos na declarao dos parmetros em uma Lambda Expressions, temos que ter uma disciplina extra em no modificar os parmetros, pois o compilador no poder nos ajudar nesses casos.

Reduzindo cdigo com Method References

Vimos at agora exemplos com Lambda Expressions, porm h mais um passo que podemos dar para deixar o codigo mais conciso:

  developers.forEach(System.out::println);

No ltimo cdigo de exemplo ns usamos um Method Reference. O Java nos deixa, de maneira simples, substituir o corpo de cdigo com um mtodo nomeado de nossa escolha. Vamos olhar com mais detalhes sobre Method Reference em artigos futuros, no worries!

Como no existe bala de prata, utilizar forEach tambm tem suas limitaes. Uma vez que comea o mtodo, diferentemente das verses que utilizam for, a iterao no podem ser interrompidas. Como consequncia, esse estilo til em casos comuns onde ns queremos processar cada elemento de uma coleo.

No prximo artigo, vamos ver como Lambda Expressions podem nos ajudar a lidar com a mutabilidade e deixar nosso cdigo mais conciso durante operaes de transformao com colees...spoiler: Streams API !!!

Obrigado a todos e at o prximo artigo!!!

Source dos exemplos 6:

Referncias:

  1. Livro:"Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expression" by Venkat Subramaniam

  2. Tell-Don't-Ask Principle by Martin Fowler

  3. JEP 323: Local-Variable Syntax for Lambda Parameters

  4. JEP 286: Local-Variable Type Inference

  5. Arquivo: Java 9 na prtica: Inferncia de tipos

  6. JBang


Original Link: https://dev.to/dearrudam/pt-br-collections-foreach-lambda-expressions-o-que-sao-external-ou-internal-iterators-1e2m

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To