List ? Hashtable ou HashMap ? Qual usar e como usar?

16 respostas
S

Olá estou com uma dúvida e gostaria se alguem poderia me ajudar?
É o seguinte tenho uma classe Usuario (bean), nela tenho apenos dois atributos Nome e Endereco.
Em uma outra classe minha, extraio as informações do nome e endereço do usuário de um arquivo texto, até aqui tudo bem o meu problema começa agora…
Aonde é melhor eu armazenas essas informações em um List do tipo Usuario? em um HashTable ou HashMap, na verdade não sei qual a diferença entre eles e qual seria o melhor ? e como fazer ?, pois antes de inserir, devo verificar se o usuário + endereço já existe se não inserir, pois precisarei mais pra frentre recuperar estas infomações, para associar com outras classes.

Segue abaixo a classe Usuario.

public class Usuario {
	
	private String nome;
	private String endereco;
	
	
	public String getEndereco() {
		return endereco;
	}
	public void setEndereco(String endereco) {
		this.endereco = endereco;
	}
	public String getNome() {
		return Nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}

Deu pra entender minha dúvida ? Desde já agradeço.

16 Respostas

soaresinfo

Se você quer recuperar dados baseado em chave única, é melhor usar algum Hash. A diferença desses que você citou é que Hashtable é uma classe melhor desenhada para aplicações multithread pois seus principais métodos são synchronized, porém essa classe é mais lenta por este motivo. Portanto, se seu aplicativo não é multithread recomendo usar o Hashmap que é mais rápido.

S

Minha aplicação não é multithread, agora eu já procurei alguma coisa sobre HashMap, mas não encontrei…se alguem puder ajudar…e soares info, valeu pelo esclarecimento.

Mauricio_Linhares

Você deve implementar o método “equals()” do seu objeto Usuario, comparando se dois usuários são iguais (comparando o nome e o endereço deles por exemplo), depois, use um Set (a implementação HashSet), que é um conjunto que não permite duplicatas, tanto HashTable, quanto List como HashMap permitem duplicatas.

Mauricio_Linhares

Você também deve implementar o método “hashCode()”, retornando valores únicos pra cada objeto. Uma maneira simples de fazer isso é simplesmente concatenar o nome o usuário com o seu endereço e retornar o “hashCode()” deles juntos.

J

Bom dia!
O HashMap parece a escolha ideal pela descrição do seu problema! No entanto, lembre-se que ao iterar em um HashMap, não é possível ter uma ordem esperada (unordered e unsorted).
Se vc quiser iterar e obter uma ordem esperada, considere o uso de TreeMap (ordem natural ou alfabética) ou LinkedHashMap (ordem de inserção).

O seguinte link pode ajudar na sua escolha:
http://www.javafree.org/javabb/viewtopic.jbb?t=847654

S

Galera, obrigado… !!!
vou estudar todas as dicas e o todo o Material, qualquer dúvida eu posto aqui novamnete…
Valeu mesmo.

S

O que eu to fazendo de Errado ?
não funciona a inclusão em um HashMap e depis recuperar o mesmo segue abaixo a classe…

public class TesteHashMap {

	
   public static void main(String args[]){
	
    Usuario u1 = new Usuario(); 	    
    Usuario u2 = new Usuario(); 	    
    HashMap hmp = new HashMap();
    	
    u1.setNome("João");
    u1.setEndereco("Sobe e desce");
    hmp.put(u1);// Aqui  o compilador já acusa um erro !!
    hmp.put(u1,0);//se eu coloco ele passa 

    u2.setNome("João2");
    u2.setEndereco("Sobe e desce2");
    hmp.put(u2);// Aqui  o compilador já acusa um erro !!
    hmp.put(u2,1); //se eu coloco ele passa

    
    for (int i = 0; i < hmp.size(); i++)
    	System.out.println(hmp.get(i)); //Ele imprime  null
}
soaresinfo

O hashmap funciona assim, você insere um objeto nele mas junto deve ir uma chave para poder recuperar aquele objeto. Se a chave da classe usuário é o nome dele concatenado ao endereço, você deveria colocar assim:

String chave = u1.getNome()+u1.getEndereco();
hmp.put(chave, u1);

note que a chamada do método exige dois parâmetros, não apenas um como você tentou.
Para recuperar o usuário é só fazer:

Usuário usu = (Usuario)hmp.get(chave);
Mantu

Sem Chance, perceba que o método put() recebe dois parâmetros do tipo Object. Funciona assim: O primeiro(chave) Object que vc passa será a chave para pesquisa que será usada toda vez que vc quiser recuperar o segundo Object(valor).
Um exemplo pra vc inserir seria algo assim:

/*Aqui guardamos cada Usuário no hmp e indexamos cada 
um através do seu respectivo nome*/
hmp.put(u1.getNome, u1);
hmp.put(u2.getNome, u2);
...
/*Aqui, vamos recuperar e imprimir na tela alguns possíveis usuários*/
Usuario currentUsuario = null;
String chave = JOptionPane.showInputDialog(null, "Entre com o nome do usuário que vc está procurando");
while(chave != null && !chave.trim().equals("")){
	currentUsuario = (Usuario)hmp.get(chave);
	String msg = "";
	if(currentUsuario == null)
		JOptionPane.showMessageDialog(null, "Usuário não cadastrado");
	else
		JOptionPane.showMessageDialog(null, "Nome: " + currentUsuario.getNome() + ", Endereço: " + currentUsuario.getEndereco());
}

Dê uma lida nesse código, e o que vc naum entender, poste aqui novamente

S

Galera, muito obrigado, pelos esclarecimentos…
Eu entendi como funciona, o HasMap, preciso de uma chave para incluir
um objeto no HasMap, mas gerou uma duvida, pois para recuperar
um usuário eu preciso dessa chave, mas no meu caso eu quero fazer um for e imprimir todos usuários, como
vou ter essa chave de cada usuário para imprimi-los ?
Aproveitando vou fazer uma outra pergunta, pois antes de inserir um objeto no HasMap, preciso
saber se o mesmo já existe ? não existindo, eu insiro, e como dito acima, apos a inserção de todos
eu gostaria de imprimir, todos os usuários cadastrados, e não apenas um ou outro.
Muito obrigado, pela paciencia e pela ajuda.

Mantu

Vamos ao mais simples primeiro:


[…]vou fazer uma outra pergunta, pois antes de inserir um objeto no HasMap, preciso saber se o mesmo já existe ?[…]

Primeiro de tudo, a suposta restrição à repetição se aplica às chaves, e não aos valores a elas associados. Mas essa “restrição”, não é bem uma restrição, vc não é obrigado a verificar se em um HashMap já existe uma chave igual a que vc quer inserir. O que acontece é o seguinte: Se vc insere um par (key1, val1) em um HashTable, no qual já exista um par (key2, val2), de tal forma que “key1.equals(key2) == true”, o método put(Object, Object) do HashMap vai trocar o valor do seu antigo par (key2, val2), deixando-o agora como (key2, val1) e ainda vai te retornar o val2, que é o valor que foi substituído. Ou seja, o put(bject key, Object val) vai inserir no HashMap o valor val associado a chave key. Se já houver na tabela uma chave que seja igual a key, o valor associado a esta chave será substituído por val e o valor antigo será retornado. Caso não exista no HashMap nenhuma chave igual a key, o par (key, value) será inserido e o put vai retornar null.
Perceba então que uma forma de saber, a posteriori, se já existe uma determinada chave no HashMap, seria simplesmente dar um put e analisar o retorno: Se for null, não tinha nenhuma chave daquela, caso contrário, já tinha.
Alternativamente, vc pode verificar a existência de uma chave antes de inserí-la, utilizando o método containsKey(Object key) que te retorna true caso a chave key exista no HashMap, e false caso contrário. Analogamente, temos o método containsValue(Object val), que analisa a existência de um valor val no HashMap.
.


[…]mas gerou uma duvida, pois para recuperar
um usuário eu preciso dessa chave, mas no meu caso eu quero fazer um for e imprimir todos usuários, como
vou ter essa chave de cada usuário para imprimi-los?[…]

Aí já complica mais um pouquinho… Existe uma interface na API Java que se chama “Set”, que representa uma coleção (Collection) de elementos não repetidos, isto é, sejam quaisquer elem1 e elem2 pertencentes a um Set mySet, elem1.equals(elem2) sempre é falso.
Tô falando sobre o Set porque existem dois métodos da classe HashMap que retornam um Set: keySet() e entrySet().
O método keySet() de um HashMap te retorna um Set que tem como elementos as chaves desse HashMap. Tendo um Set “nas mãos” vc pode iterar sobre as chaves através de um Iterator(retornado pelo método iterator() da interface Set) ou de um array simples(retornado pelos métodos toArray() e toArray(Object[]) ). É importante citar alguns poréns que eu tava lendo na API: 1) Se vc excluir alguma chave no HashMap que originou o Set, tal chave será excluida também do Set, e vice-versa. 2) Os métodos add(Object) e addAll(Collection) da interface Set, não são suportados por um Set obtido através do retorno do método keySet() de um HashMap.
Agora… quanto ao método entrySet(), temos uma pegadinha… Se temos um HashTable que tem, por exemplo, um mapeamento de chaves do tipo String e valores do tipo File, algo como (strKey, fileVal), o Set retornado pelo seu keySet() terá elementos Object que “podem ser convertidos” para String.
Já o entrySet(), faz quase a mesma coisa que o keySet(): Te retorna um Set com os valores do HashMap, só que não será um Set com Object “conversíveis” para File, neste nosso exemplo… O Set retornado pelo entrySet() sempre tem elementos do “tipo” Entry, que é uma interface interna e pública da interface Map. O que isso quer dizer? Quer dizer que, por exemplo, na primeira posição do nosso Set, não teremos um File, e sim um Entry.
A interface Entry representa um mapeamente (chave,valor). Embora pareça uma idiotice retornar um Set de Entry ao invez de, no nosso exemplo, um Set de File, isso faz muito sentido: Lembra que um Set não tem elementos repetidos? Agora, perceba que um HashMap não tem chaves repetidas, mas duas(ou mais) chaves diferentes podem armazenar valores iguais. Senda assim, se o entrySet() não tem como retornar um Set dos valores contidos em um HashMap, pois não há garantias de que só temos valores diferentes. Daí a jogada do Set de Entry, que garante a unicidade de cada elemento do Set, pois cada mapeamento (chave,valor) no HashMap é único.
O fato do retorno do entrySet() ser um Set de Entry implica que, quando vc for iterar sobre um Set obtdo pela invocação deste método, vc terá que: 1)converter o elemento para Entry(Por que o Set sempre “cospe” seus elementos com usando o tipo Object), 2)invocar o método getValue(), que te retorna um Object referente ao valor do mapeamento (chave,valor), representado pelo Entry, 3)Converter esse Object retornado, no nosso exemplo, em um File.
Ficaria algo assim:

...
HashMap myHashMap = new HashMap();
.../*Suponha que aqui o myHashMap foi alimentado*/
/*Vamos escrever na tela todos os valores armazenados no nosso 
HashMap, que são objetos do tipo File, neste exemplo*/
Set values = myHashMap.entrySet();
Iterator myIterator = values.iterator();
System.out.println("Listando arquivos contidos no HashMap myHashMap:");
while(myIterator.hasNext()){
	Entry myEntry = (Entry)myIterator.next();
	File myFile = (File)myEntry.getValue();
	/* De um modo mais abreviado ficaria assim:
	File myFile = (File)((Entry)myIterator.next()).getValue()
	*/
	System.out.println("\t" + myFile.getName());
}
...

É isso, espero ter ajudado!
Qq coisa, pergunte. ok!

S

Mantu, desculpe abusar da sua bondade, mas ao rodar o código que você disponibilizou da o erro abaixo

Exception in thread “main” java.lang.ClassCastException: br.com.teste.modelo.Usuario
at br.com.teste.TesteHashMap.main(TesteHashMap.java:43)

O conteúdo da linha 43 é esse : File myFile = (File)((Entry)myIterator.next()).getValue();

E desculpe, mas não entendi pq não posso utilizar o keySet() e sim o entrySet(), pois para meu exemplo basta eu armazenar as informações no hashMap(desde que não sejam repetidas (isso eu consegui fazer!!!)), e sabendo que as mesmas não são repetidas, tenho apenas que listar todos as informações armazenas no hashMap, no caso listar todos os nomes e endereços dos usuarios.
Se vc puder me ajudar novamete…Muito Obrigado.

S

Pra facilitar olha como esta minha classe:
Fiz um for para incluir o mesmo usuário´vário vezes e validar se o mesmo é armazenado e impresso uma só vez.

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;

public class TesteHashMap {

	public static void main(String args[]){
 	    
	HashMap hmp = new HashMap();   

	for (int i=0; i<5 ; i++){
		Usuario u = new Usuario();
		u.setNome("João");
		u.setEndereco("Rua São Sebastião");   

		if (hmp.containsKey(u.getNome())){
			System.out.println("repetido ");
		}else{
			hmp.put(u.getNome(), u);
		}	       
	} 
    Set values = hmp.entrySet();
    Iterator myIterator = values.iterator();
    System.out.println("Listando arquivos contidos no HashMap myHashMap:");
    while(myIterator.hasNext()){    	
    	File myFile = (File)((Entry)myIterator.next()).getValue();    	
    	System.out.println("\t" + myFile.getName());
    }
	
  }
}
Mantu

Perceba o seguinte: No exemplo que eu postei, o nosso HashMap armazenava objetos File, no seu exemplo, o HashMap armazena objetos Usuario. Os Entry do meu exemplo, logo, fazem o mepeamento (String key,File value), já o seu, faz um mapeamento (String key, Usuario value).
Sendo assim, pra eu recuperar o valor do meu entry eu tenho que dar um cast pro tipo que tá guardado lá dentro, como eu fiz no meu exemplo:

File myFile = (File)myEntry.getValue();

Vc deveria ter alterado essa linha, pois o seu entry guarda não mais objetos File, e sim objetos Usuario

Usuario myUsuario = (Usuario)myEntry.getValue();.
Quanto ao lance de usar keySet() ou entrySet(), vc pode usar qualquer um deles pro seu caso, só que a implementação ficaria diferente. A que usa entrySet() vc já fez, só esqueceu que o “Ctrl+C, Ctrl+V” nos prega algumas peças… :lol:
Se for fazer usando um Set proveniente do método keySet(), é mais fácil, por que vc só vai ter que ficar tirando do set e jogando no HashMap pra recuperar o seus usuários. Só que eu acho, não tenho certeza, que assim é menos performático… por que o Java vai ter que buscar cada chave dentro do HashMap, sacou?

...
Set keys = myHashMap.keySet();
Iterator myIterator = keys.iterator();
...
while(myIterator.hasNext()){
	Object key = myIterator.next();
	Usuario myUsuario = (Usuario)myHashMap.get(key);
	System.out....
}

Tenta primeiro corrigir o que eu te disse que vc errou e vê se roda, depooois, vc tenta usar a estratégio do keySet(). É bom pra praticar, hehehehe
Qq coisa, poste mais, ok?

S

Mantu, Cara, obrigado, pela aula, valeu mesmo…vc me ajudou muito, e desculpa pela ignorancia… no Ctrl+C, Ctrl+V" , funcionou tanto com o keyset(), como o entrySet(), mas acredito tb que performaticamente o entrSet() eu tenha algum ganho…
e mais uma vez Obrigado.

R

oi ai esta meu codigo

import java.io.*;         
          import java.util.HashMap;  
          import java.util.ArrayList;    
          import java.util.List;    
          import java.util.Map;    
          //import javax.swing.JOptionPane;   
      
      
                     
        public class Dados{             
                   
              
            //"args" é um array de String onde cada elemento é um argumento passado pela linha de comando momento na "inicialização" da execução.  
            public static void main(String[] args){             
                  
                  
               Map<Integer, List<String>> mapLines= new HashMap<Integer, List<String>>();       
             try {             
               //leitura do ficheiro, prepara-o para ser aberto  
               BufferedReader in = new BufferedReader(new FileReader("conteudo.txt"));             
               String str;         
               int i = 0;         
               //vai percorrer todo o ficheiro  
               while((str = in.readLine()) != null)             
               {                   
                   if(str.startsWith("#"))  
                   {                   
                       str= "";                   
                   }                   
                   else{     //esta a dividir a frase em varias strings imprimindo o seu resultado  
                        List<String> values = new ArrayList<String>();       
                            String words[] = str.split(";");           
                            for(String word : words) {           
                                values.add(word);   
                                System.out.println(word);  
                            }       
                            mapLines.put(i, values);       
                            i++;       
                   }     
             }// fim do while                             
               in.close();             
           }  catch (IOException e){             
               // possiveis erros são tratatos aqui   
               //JOptionPane.showMessageDialog(null, this.word, "NÂO FOI POSSÍVEL ABRIR O SEU FICHEIRO", JOptionPane.ERROR_MESSAGE);    
               System.out.println("ERRO-->NÃO FOI ENCONTRADO O SEU FICHEIRO DE DESTINO,TENTE DE NOVO");          
           }        
           // Apresenta o contéudo do Map       
           Map<Integer, List<String>> m = new HashMap<Integer, List<String>>();       
           for(Integer key : m.keySet()) {       
               for(String word : m.get(key)) {       
                   System.out.println(word);       
               }       
           }                
           }   
            public static void main2(String[] args){             
                  
                  
                Map<Integer, List<String>> mapLines= new HashMap<Integer, List<String>>();       
             try {             
                        
               BufferedReader in2 = new BufferedReader(new FileReader("conteudo2.txt"));             
               String str;         
               int i = 0;         
               while((str = in2.readLine()) != null)             
               {                   
                   if(str.startsWith("#"))                   
                   {                   
                       str= "";                   
                   }                   
                   else{     //esta a dividir a frase em varias strings  
                            List<String> values = new ArrayList<String>();       
                            String words[] = str.split(" ");           
                            for(String word : words) {           
                                values.add(word);  
                                System.out.println(word);  
                            }       
                            mapLines.put(i, values);       
                            i++;       
                   }     
             }// fim do while                             
               in2.close();             
           }  catch (IOException e){             
               // possiveis erros são tratatos aqui    
               System.out.println("ERRO-->NÃO FOI ENCONTRADO O SEU FICHEIRO DE DESTINO,TENTE DE NOVO");  
           }        
           // Apresenta o contéudo do Map       
           Map<Integer, List<String>> m = new HashMap<Integer, List<String>>();       
           for(Integer key : m.keySet()) {       
               for(String word : m.get(key)) {       
                   System.out.println(word);       
             
                }     
      
            }  
        }  
    }

e tenho por exemplo este ficheiro

view plaincopy to clipboardprint?

961234567 253883377 24:05:2011 10:30:10 068 16 13  
    963456789 253883355 28:05:2011 12:15:17 088 12 09  
    963456789 253883377 29:05:2011 17:00:00 120 14 11  
    969876666 253883377 30:05:2011 10:05:34 070 11 09  
    961234567 253883377 31:05:2011 22:30:05 066 14 11  
    961234567 253883377 02:06:2011 14:19:41 076 15 13  
    963456789 253883377 05:06:2011 11:33:34 085 07 06

e queria que fosse pedido ao utilizador que dados e que ele quer imprimir. por exemplo...pedirmos para imprimir todos os dados com o numero 961234567

abraços

Criado 5 de junho de 2006
Ultima resposta 27 de jun. de 2011
Respostas 16
Participantes 6