Extendendo a classe ArrayList para criar listas sem repetição

Publicado por Pedro Ferrarezi em 20/12/2013

[ Hits: 12.766 ]

 


Extendendo a classe ArrayList para criar listas sem repetição



Olá, amigos do VOL.

Hoje, deixo uma dica sobre como criar, rapidamente, listas de vetores/arrays sem repetição, em Java.

Estou deixando essa dica, porque depois de "googlar" por horas e horas, não achei um código decente que fizesse o acima.

O que mais se acha na Net, são usuários avançados sugerindo implementar comparable e iterator. Mas isso gera um código grande e complexo, e nem sempre atende a todas às necessidades.

Eu até vi alguns usuários bravos no Stack Overflow dizendo que em C++, a classe std::Set provê isso com facilidade, e que Java só faz a gente passar raiva. Mas, eu acho que não é bem por aí. Java também te dá isso, mas por um caminho mais longo, só isso.

A solução que acabei chegando depois de muita dor, tentativa e erro, foi estender a classe ArrayList e sobrecarregar o método contains(), e é isso que vou explicar como fazer.

Primeiro, crie uma classe que estende a classe ArrayList, como abaixo:

import java.util.ArrayList;
import java.util.Arrays;

public class Lista<T> extends ArrayList<T>{

    public Lista() {
        super(); //chame o construtor de ArrayList
    }

    /*Esse método sobrecarrega o metodo contains, e irá funcionar
    com arrays de objetos. Você pode sobregarregar, sobrescrever
    ou adicionar mais métodos a esta classe, de forma que
    ela fique ainda mais poderosa, e usar ela, em vez de ArrayList.
    */

    public boolean contains(Object[] o){
        //percorre o bjeto 'Lista':
        for(int i=0; i< this.size(); i++){
            /* cria um array de objetos e faz um 'type-cast'
            desta própria classe atribuindo a ele o valor do
            elemento, e isso para cada elemento, de forma que
            todos os elementos sejam tratados como arrays de
            objetos:
            */

            Object[] toCompare = (Object[])this.get(i);
            /* através do metodo equals da classe Arrays, e do loop
            for-each, verifica se algum elemento do array candidato ao
            add() já está adicionado na lista, se sim é retornado true,
            se não, é retornado false.
            */

            if(Arrays.equals(o, toCompare)){
                return true;
            }
        }
        return false;
    }
}

Para testar se a classe está funcionando, crie uma classe principal e chame-a, tente adicionar registros repetidos e teste o conteúdo das listas de arrays depois, assim:

public static void main(String[] args) {
Lista<Object[]> lista = new Lista<Object[]>(); //Instancia a classe que criamos

        for(int i=0; i<100; i++){ //tenta inserir 100x a mesma coisa
            if(!lista.contains(new Object[]{ "bbb", true, 132.0, 1234 })) //Observe que existem vários tipos de dados nesse array
                lista.add(new Object[]{ "bbb", true, 132.0, 1234 });

            if(!lista.contains(new Object[]{ "aaa", false, 132.0, 1234 }))
                lista.add(new Object[]{ "aaa", false, 132.0, 1234 });
        }

        for(int j=0; j<lista.size(); j++){
            for(int c=0; c<lista.get(j).length; c++){
                System.out.print(lista.get(j)[c]+"-");
            }
            System.out.print("\n");
        }
    }

A saída no console, será:
bbb-true-132.0-1234-
aaa-false-132.0-1234-

Foram inseridos apenas 2 arrays na lista. :)

Um abraço a todos.
Espero que ajude.

Outras dicas deste autor

Debian/Ubuntu - Conectando banco MySQL via rede com Java

Backup poderoso e automatizado combinando 7-Zip + head + cron

Sublime Text Editor 2 - Instalando e integrando no Ubuntu 12.04

Montando um servidor de remote desktop com NX Server

Como mudar o teclado do Debian em uma máquina virtual configurada em outro SO

Leitura recomendada

Arquivos .jar

Java Web Services Developer Pack

Treinamento gratuito online de Java

Eclipse Helios: Resolvendo problemas com o proxy

Programa para visualizar graficamente sua rede de amizades no Orkut

  

Comentários
[1] Comentário enviado por maiconramones em 20/12/2013 - 10:27h

Prezado Pedro,

Acho que você está começando a programar em Java, a sua solução não é a mais recomendada. Porque?

O Java já possui um conjunto de classes que não permitem elementos duplicados. Essas classes implementam a interface Set, você pode conferir mais informações na documentação aqui -> http://docs.oracle.com/javase/7/docs/api/index.html?java/util/Set.html.
Nesse link (http://javafree.uol.com.br/artigo/847654/) em português do JavaFree tem uma excelente explicação sobre as classes da API padrão que trabalham com coleções.

Espero ter ajudado

[2] Comentário enviado por ferrarezux em 20/12/2013 - 12:29h

Obrigado maiconramones. Mas leia o que eu disse na minha dica por favor.

[3] Comentário enviado por aronrodrigues em 06/01/2014 - 11:24h

Pedro, o que o Maicon falou é verdade.

"O que mais se acha na Net, são usuários avançados sugerindo implementar comparable e iterator. Mas isso gera um código grande e complexo, e nem sempre atende a todas às necessidades. "

O que você está fazendo no seu ArrayList é a mesma coisa que a interface Set faz.

Utiliza o comparable para verificar se o objeto já existe. Só que no seu código, a cada inserção você varre a lista (o que torna seu codigo MUITO lento).

Faça o teste, com um Set e com sua classe, para ver o resultado. (tente a partir de 100.000 elementos para ter noção do tempo).

Além disso sua classe tem um GRANDE problema, que é a de não ser aceita por outras bibliotecas (por exemplo ORM). Se você persistir sua classe no banco, o que o container vai te retornar será uma interface de List. E não da sua classe.

Para fazer do jeito certo, basta você usar o Set (vai funcionar igualizinho sua classe).

A interface Comparable (metodo compare), só deve ser sobrescrita se você quiser mudar a verificação padrão (exatamente o mesmo objeto) para uma comparação por exemplo, pelo ID.

Se quiser, me mande um email que te explico direitinho...



Contribuir com comentário