25%OFF no 1º ano | 50%OFF No 2º ano

Últimos dias!

Últimos dias!

00

DIAS

00

HORAS

00

MIN

00

SEG

Visitando uma Collection em ordem inversa

Visitando uma Collection em ordem inversa
peas
peas

Compartilhe

As vezes troco algumas mensagens bem técnicas com alguns colegas pelo GTalk, e aí aparecem algumas charadas interessantes.

O Orseni Campos, um desenvolvedor que eu admiro muito, passou o seguinte problema: "Paulo, como percorrer uma coleção qualquer na ordem inversa de maneira elegante?". Quando ele disse maneira elegante, pensei que ele queria evitar criar uma lista e acessá-la via lista.get(indice) de trás para frente. Respondi o trivial: que o Collections.reverse resolveria: ```java public void imprimeInvertidoClassico(Collection<? extends Object> colecao) { List invertida = new ArrayList(colecao); Collections.reverse(invertida); for (Object objeto : invertida) { System.out.println(objeto); } }


Ele não gostou, queria uma maneira de percorrer a coleção invertida sem criar uma coleção temporária, nem mexer na ordem dos objetos da coleção dada.

Desisti. Ele respondeu: "_basta visitar a coleção recursivamente, realizando a ação como pós processamento!_". Perfeito. Uma técnica das [linguagens funcionais](http://en.wikipedia.org/wiki/Functional_programming) e adorada pelos professores de conceitos de linguagens. Aliás, universidades importantes como MIT utilizam linguagens funcionais no curso introdutório de computação, acreditam que é mais fácil do aluno assimilar os conceitos dos algoritmos ([algumas dessas linguagens](http://en.wikipedia.org/wiki/Scheme_programming_language) são dos [mesmos criadores do Java](http://en.wikipedia.org/wiki/Guy_L._Steele)).

Então traduzi a idéia para código: ```java
 public void imprimeInvertido(Collection<? extends Object> colecao) { imprimeInvertido(colecao.iterator()); }

private void imprimeInvertido(Iterator<? extends Object> iterator) { if (iterator.hasNext()) { Object object = iterator.next(); imprimeInvertido(iterator); System.out.println(object); } } 
Banner da Black Friday da Alura com destaque para até 50% de desconto em cursos, válido até 29/11. Transforme a sua carreira com o maior desconto do ano, matricule-se já!

Aqui, o método imprimeInvertido rapidamente delega a responsabilidade para o que recebe um Iterator como argumento. Este faz uma invocação recursiva no caso de existir um próximo elemento a ser visitado. O importante aqui é que a referência trazida pelo iterator.next() só é processado depois que seus elementos vizinhos forem, realizando o processo na ordem contrária da determinada pelo Iterator. (repare que considerando que a ordem definida pelo Iterator define uma lista, e que toda lista é uma árvore, estamos percorrendo essa ávore de maneira pós-fixa).

Ok, funciona e não cria coleção temporária! Mas se você parar para analisar bem, cada invocação recursiva empilha mais um stackframe, e em cada um temos uma variável temporária (a Object object declarado dentro do if) para ser recuperada quando a invocação retornar. Pensando na última invocação (base da recursão, quando o iterator chegar ao final e não entrar no if (iterator.hasNext())) teremos uma pilha com colecao.size() stackframes, alocando uma memória proporcional ao tamanho da coleção, muito semelhante a ter alocado a coleção temporária para o Collections.reverse.

Você ainda corre o risco de um StackOverflowError por estar gastando memória da pilha em vez do heap! Outra desvantagem é a legibilidade: nós programadores java não estamos acostumados a utilizar recursão para resolver problemas que poderiam ser facilmente resolvidos de maneira iterativa.

O exercício vale para relembrar que é importante manter contato com outras linguagens, para não ficar viciado no mesmo paradigma, o que te limita na hora de encontrar soluções. Em alguns casos a solução recursiva pode ser muito mais trivial de encontrar, desde que você esteja com o paradigma afiado!

Alguma outra maneira interessante de percorrer uma coleção na ordem inversa?

Veja outros artigos sobre Programação