Existe algo mais rapido que ArrayList em Java?

Olá pessoal, estou fazendo um programa que usa muitas iterações em Lista (Adiciona, remover e alterar elementos), e esta ficando bem lento.

Estou usando ArrayList e JDK 1.7 e ListIterator, existe algo melhor para usar e ter maior performance com Lista em java?

alguns exemplo do codigo a seguir:

public void adiciona_modificacoes(ArrayList<Modificacao> novas_modificacoes) { Modificacao aux; ListIterator<Modificacao> i = novas_modificacoes.listIterator(); while(i.hasNext()) { aux = i.next(); if(aux.classee.equals(this.nome)) { this.modificacoes.add(aux); i.remove(); } } }

você realmente precisa que suas listas sejam listas?

Até aonde eu sei o HashSet é mais rápido que o ArrayList mas tem algumas restrições.

olá, sempre procuro usar vetor, ainda mais sendo em Java, porem nesse caso é inviavel, um resumo do problema é assim:

A cada modificação feita por qualquer cliente vai para uma lista temporaria, caso o cliente salve essas modificações devem ir para o historico desse cliente especifico e sair da lista temporaria, o processamento de modificações é feito com todos os clientes misturados, e no final tenho de ordenar essa lista de modicações de cada cliente por data .

até onde sei HashTree ( arvore binaria ) é mais rápida que ArrayList (lista encadeada) :slight_smile:

uhh, vou testar, tem algum exemplo de HashTree para me passar ae? Mas como tenho que percorrer a lista inteira e remover e adicionar varios elementos, acho que a arvore vai ficar ainda mais lento, arvore geralmente compensa para buscar rapidamente.

Existem diversas coleções que são mais “rápidas” tudo depende da situação em que você se encontra.

No seu caso, acho que você não fez uma boa escolha, um cliente tem que iterar por alterações que não são nem dele, isso não ficou legal.

Uma coisa que pode deixar as coisas mais rápidas é fazer um HashMap<Cliente, Alteracoes>, assim quando você tiver o cliente que quer, você busca diretamente as alterações dele em um HashMap, agora se as Alteracoes realmente precisam ser uma lista, isso ainda não ficou claro para mim.

Entendeu a sugestão ?

Pretendes fazer um log de todas as alterações?
Eu utilizo o Hibernate Envers pra isso.
Ele registra todas as inclusões, alterações e exclusões, gravando um timestamp

[quote=digaoneves]Existem diversas coleções que são mais “rápidas” tudo depende da situação em que você se encontra.

No seu caso, acho que você não fez uma boa escolha, um cliente tem que iterar por alterações que não são nem dele, isso não ficou legal.

Uma coisa que pode deixar as coisas mais rápidas é fazer um HashMap<Cliente, Alteracoes>, assim quando você tiver o cliente que quer, você busca diretamente as alterações dele em um HashMap, agora se as Alteracoes realmente precisam ser uma lista, isso ainda não ficou claro para mim.

Entendeu a sugestão ?[/quote]

Entendi sim, parece que é isso que eu preciso, é que nunca usei HashMap antes, vou dar uma pesquisada obrigado.

Sim, o Cliente tem de passar por alterações que não são dele e isso prejudica, mas o maior problema e a remoção e ordenação que demoram mto quando a lista tem mais de 1000 elementos.

[quote=asandrob]Pretendes fazer um log de todas as alterações?
Eu utilizo o Hibernate Envers pra isso.
Ele registra todas as inclusões, alterações e exclusões, gravando um timestamp[/quote]

Obrigado, mas não é log de alterações em banco de dados, se for isso que o Hibernate Envers faz.

São eventos que são enviados para um administrador, a unica coisa gravada no banco é o resultado final de todas as modificações

Bah, fico imaginando se dá um pau no teu sistema. Uma lista com mais de 1000 elementos se perdendo, e o cliente tendo que fazer tudo denovo…
Eu gravaria todos esses registros com alguns STATUS (STATUS.Temporario STATUS.Definitivo) e quando o teu cliente “gravar” só troca o STATUS…

Acho mais seguro.

[quote=jaozi_nho]
Entendi sim, parece que é isso que eu preciso, é que nunca usei HashMap antes, vou dar uma pesquisada obrigado.

Sim, o Cliente tem de passar por alterações que não são dele e isso prejudica, mas o maior problema e a remoção e ordenação que demoram mto quando a lista tem mais de 1000 elementos.[/quote]

Certo… a implementação do HashMap é simples, ele tem uma chave, e um valor. a chave é única, portanto se você usar o Cliente como chave, você não terá o mesmo cliente 2x no HashMap.

então você vai ter algo como:Map<Cliente, List<Alteracao>> mapAlteracoes; E quando tiver o cliente específico e quiser somente as alterações dele, faz assim:List<Alteracao> alteracoesCliente = mapAlteracoes.get(cliente); Entendeu?

[quote=jaozi_nho]Olá pessoal, estou fazendo um programa que usa muitas iterações em Lista (Adiciona, remover e alterar elementos), e esta ficando bem lento.

Estou usando ArrayList e JDK 1.7 e ListIterator, existe algo melhor para usar e ter maior performance com Lista em java?

alguns exemplo do codigo a seguir:

public void adiciona_modificacoes(ArrayList<Modificacao> novas_modificacoes) { Modificacao aux; ListIterator<Modificacao> i = novas_modificacoes.listIterator(); while(i.hasNext()) { aux = i.next(); if(aux.classee.equals(this.nome)) { this.modificacoes.add(aux); i.remove(); } } }[/quote]

Engraçado que alguém pergunta se tem algo mais rápido que arraylist e não faltam sugestões :lol:
Mais em rápido em quê ?
É muito rápido iterar um ArrayList, e mudar para Set não muda em nada isso. O Set não é nem mais rápido nem mais lento porque faz coisas diferentes!
Mas vc está removendo da lista. Ai que está o problema remover de um ArrayList é o pior cenário possivel.

O seu design é fraco e complexo. Vamos mudar algumas coisas assim :

[code]public void adiciona_modificacoes(List novas_modificacoes) // parametros devem ser interfaces
{

 for (Iterator<Modificacao> it = novas_modificacoes.iterator(); it.hasNext(); ){ // basta usar iterator, e não ListIterator

         Modificacao aux = it.next();

        if(aux.classee.equals(this.nome))
        {
            this.modificacoes.add(aux); // aqui ha uma adição em outra coleção.
            it.remove(); // aqui ha a remoção do item
        }

}

}[/code]

bom, agora é claro que este código terá performance diferente comforme a lista passada.
Sempre que ha um remove, o arrayList é obrigado a criar um novo array e copiar o anterior excepto o elemento apagado. Isto é lento.
A implementação mais rápida para isso é LinkedList. Então, seria bom ter a certeza que se passa um LinkeList. Mas como é uma parametro, isso significa que ha que fazer alterações em algum outro lugar do sistema.

Veja que mesmo usando LinkedList o tempo de execução ainda está ligado a quantos itens existem na lista. Isso também afeta o resultado. MAs para o mesmo numero , grande de itens, o LinekdList é mais rápido na remoção.

O resumo da opera é o seguinte:
A Iteração em si é igualmente rápida no ArrayList ou no LinkedList. A Adição e Remoção aleatória ( no meio da lista) é sempra mais rápida no LinkedList ( é para isso que ele foi inventado). A inserção simples, sequencial (sempre no fim) é mais rápida no ArrayList se , e somente se, o tamanho máximo da lista é conhecidoà priori e passado no construtor, caso contrário a inserção simples e sequencial é mais rápida no LinkedList.

Mudar para Set não afeta o resultado. A única operação mais rápida no Set que no resto é o contains.

Uma nota sobre o for vs while : o resultado é o mesmo, mas o for é especialmente criado para iterações. Ele poupa memória porque o iterador é descartado ao sair do for, assim como a variável auxiliar. Usando while, estas variáveis ficam presentes até sair do método. Além disso, usar while obriga a escrever mais e torna o código menos legeivel. A falta de legibilidade, por sua vez, esconde problemas que seriam obvios se houvesse menos codigo para ler.

[quote=asandrob]Bah, fico imaginando se dá um pau no teu sistema. Uma lista com mais de 1000 elementos se perdendo, e o cliente tendo que fazer tudo denovo…
Eu gravaria todos esses registros com alguns STATUS (STATUS.Temporario STATUS.Definitivo) e quando o teu cliente “gravar” só troca o STATUS…

Acho mais seguro.[/quote]

Tipo se o sistema cair nenhuma modificação pode ser salva mesmo, ele tem de fazer tudo de novo mesmo, pois essas modificações são coletas de outro sistema.

Uhhh, sobre os status acho que ficaria mais lerdo essa implementação, pois teria de passar por toda a lista de modificações ja gravadas e ir procurando pelas temporarias para trocar de status, mas vlw pela ajuda.

Sobre o HashMap entendi sim, mto obrigado @digaoneves

@sergiotaborda

Uhh não sabia que LinkedList e ArrayList tinham tantas diferenças, me esclareceu bastante, vou testar com o HashMap, acho que faz mais sentido para este problema, se não ficar legal troco para LinkedList.

Vlw pelas dicas do For e While tb

sergiotaborda
Se me permite aproveitar o gancho, gostaria de tirar umas dúvidas sobre o seguinte caso:

Nota: os nomes de classes e atributos são de exemplo:[code]
// objetos usados pela classe gerencia
public class UmObjeto{
private String texto;
private double valor;

public void desenhar(){…}
}

// classe que utiliza os objetos variados
public class Gerencia{
private List lista;

public Gerencia(){
lista = new ArrayList(); // um linkedlist
}

public void desenhar(){
for(UmObjeto obj : lista){
obj.desenhar();
}
}

public void removerAlguns(){…}

public void adicionar(UmObjeto obj){lista.add(obj);}

}[/code]Considerando o que você colocou sobre ArrayLists e LinkedLists, além do seguinte:

  • o método adicionar() pode ser executado diversas vezes em momentos aleatórios (clique do usuário, por exemplo);
  • o método removerAlguns() (que remove os elementos de acordo com algum critério) também pode, igualmente, ser executado diversas vezes em momentos aleatórios, excluindo da lista elementos em posições variadas (através de uma lista auxiliar e do removeAll());
  • o método desenhar() é o mais executado (praticamente qualquer ação do usuário, como pressionar uma tecla ou mover a tela, o executa) e itera a lista constantemente a lista;

Me parece então que, para este caso, o LinkedList se adequa melhor, certo? De todo modo, uma vez que acompanhei o tópico, tentarei fazer alguns testes por aqui.

Abraço.

[quote=TerraSkilll]sergiotaborda
Se me permite aproveitar o gancho, gostaria de tirar umas dúvidas sobre o seguinte caso:

Nota: os nomes de classes e atributos são de exemplo:[code]
// objetos usados pela classe gerencia
public class UmObjeto{
private String texto;
private double valor;

public void desenhar(){…}
}

// classe que utiliza os objetos variados
public class Gerencia{
private List lista;

public Gerencia(){
lista = new ArrayList(); // um linkedlist
}

public void desenhar(){
for(UmObjeto obj : lista){
obj.desenhar();
}
}

public void removerAlguns(){…}

public void adicionar(UmObjeto obj){lista.add(obj);}

}[/code]Considerando o que você colocou sobre ArrayLists e LinkedLists, além do seguinte:

  • o método adicionar() pode ser executado diversas vezes em momentos aleatórios (clique do usuário, por exemplo);
  • o método removerAlguns() (que remove os elementos de acordo com algum critério) também pode, igualmente, ser executado diversas vezes em momentos aleatórios, excluindo da lista elementos em posições variadas (através de uma lista auxiliar e do removeAll());
  • o método desenhar() é o mais executado (praticamente qualquer ação do usuário, como pressionar uma tecla ou mover a tela, o executa) e itera a lista constantemente a lista;

Me parece então que, para este caso, o LinkedList se adequa melhor, certo? De todo modo, uma vez que acompanhei o tópico, tentarei fazer alguns testes por aqui.

Abraço.[/quote]

O seu caso é ligeriamente diferente.
Primeiro temos a questão de que o list pode sofrer modificações em momentos “aleatórios”.
Por outro lado, vc precisa iterar ao mesmo tempo que modifica. Isto por si só elimina a possibilidade de usar tanto o arraylist como o linkedlist que não permitem que a lista seja adicionada enquanto está sendo iterada. Isto está gritando “Concurrencia”. Então o caso aqui seria de tentar entender se precisamos de lista que suporte concorrencia.

O seu exemplo é um exemplo classico do padrão Composite onde um objeto é composto por uma lista de outras e opera sobre esta lista.
Neste cenário, antigamente, apenas poderiamos utilizar syncronized em todos os métodos para garantir que não dá problema, e usar LinkedList. Hoje em dia, pós java 5, temos outras opções.

A solução aqui seria usar CopyOnWriteArrayList.
Isto porque esta classe suporta modificações ao mesmo tempo que itera, o que é o ideal para o processamento do seu caso.

Existem muitas implementações de list, e cada uma serve um cenário. É bom a todos o programador java conhecer a API de coleções como a palma da mão e saber qual implementação é boa em qual cenário. De notar que dependendo do cenário e da implementação escolhida o algoritmo pode não funcionar como esperado ou dar erros que não serão uma surpresa se não se sabe qual é o comportamento especifico da implementação.

sergiotaborda
Opa, acho que não fui claro e acabei te confundindo, desculpe.

As iterações e inserções não são concorrentes. Quando disse que elas ocorrem em momentos aleatórios, quis dizer que, a qualquer momento, pode ser necessária a chamada a algum dos métodos, por causa da interação do usuário. Eu não modifico a lista em si (adicionando/removendo) enquanto a itero, mas pego um dos elementos dela e altero suas propriedades internas (texto e valor, por exemplo). Não sei se isso invalida a sua explicação, mas agradeço pelas explicações até aqui.

Abraço.

[quote=TerraSkilll]sergiotaborda
Opa, acho que não fui claro e acabei te confundindo, desculpe.

As iterações e inserções não são concorrentes. Quando disse que elas ocorrem em momentos aleatórios, quis dizer que, a qualquer momento, pode ser necessária a chamada a algum dos métodos, por causa da interação do usuário. Eu não modifico a lista em si (adicionando/removendo) enquanto a itero, mas pego um dos elementos dela e altero suas propriedades internas (texto e valor, por exemplo). Não sei se isso invalida a sua explicação, mas agradeço pelas explicações até aqui.

Abraço.[/quote]

Se vc tem a certeza que não ha concorrencia, então fique com o LinkedList mesmo.

LinkedList resolveu meu problema, agora inserções e remoções são feitas mto rapido, como não uso lista.get(n) usar ArrayList não me oferecia nenhuma vantagem.

vlw a todos pelas respostas!