A Collection
- a volte chiamato contenitore - è semplicemente un oggetto che raggruppa più elementi in una singola unità. Collection
vengono utilizzati per archiviare, recuperare, manipolare e comunicare dati aggregati. Un framework di raccolte W è un'architettura unificata per rappresentare e manipolare raccolte.
La HashMap
JDK1.2
e Hashtable JDK1.0
, entrambi sono utilizzati per rappresentare un gruppo di oggetti che sono rappresentati in <Key, Value>
coppia. Ogni <Key, Value>
coppia è chiamata Entry
oggetto. La raccolta di voci è indicata dall'oggetto di HashMap
e Hashtable
. Le chiavi in una raccolta devono essere uniche o distintive. [in quanto vengono utilizzati per recuperare un valore mappato una chiave particolare. i valori in una raccolta possono essere duplicati.]
« Membro di Superclass, Legacy e Collection Framework
Hashtable è una classe legacy introdotta in JDK1.0
, che è una sottoclasse della classe Dictionary. Da JDK1.2
Hashtable è stato riprogettato per implementare l' interfaccia Map per creare un membro del framework di raccolta. HashMap è un membro di Java Collection Framework sin dall'inizio della sua introduzione in JDK1.2
. HashMap è la sottoclasse della classe AbstractMap.
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable { ... }
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { ... }
« Capacità iniziale e fattore di carico
La capacità è il numero di bucket nella tabella hash e la capacità iniziale è semplicemente la capacità al momento della creazione della tabella hash. Si noti che la tabella hash è aperta: nel caso di un " hash
collision
", un singolo bucket memorizza più voci, che devono essere ricercate in sequenza. Il fattore di carico è una misura della quantità massima consentita dalla tabella hash prima di aumentare automaticamente la sua capacità.
HashMap costruisce una tabella hash vuota con la capacità iniziale predefinita (16) e il fattore di carico predefinito (0,75). Dove come Hashtable costruisce hashtable vuoto con una capacità iniziale predefinita (11) e un fattore di carico / rapporto di riempimento (0,75).
« Modifica strutturale in caso di collisione dell'hash
HashMap
, Hashtable
in caso di collisioni hash memorizzano le voci della mappa in elenchi collegati. Da Java8 perHashMap
se il bucket hash cresce oltre una certa soglia, il bucket passa da linked list of entries to a balanced tree
. che migliorano le prestazioni nel caso peggiore da O (n) a O (log n). Durante la conversione dell'elenco in albero binario, l'hashcode viene utilizzato come variabile di ramificazione. Se ci sono due diversi hashcode nello stesso bucket, uno è considerato più grande e va a destra dell'albero e l'altro a sinistra. Ma quando entrambi gli hashcode sono uguali, HashMap
presuppone che le chiavi siano comparabili e confronta la chiave per determinare la direzione in modo da mantenere un certo ordine. È buona norma rendere le chiavi HashMap
comparabili . All'aggiunta di voci se la dimensione del bucket raggiungeTREEIFY_THRESHOLD = 8
converte un elenco di voci collegate in un albero bilanciato, rimuovendo le voci meno TREEIFY_THRESHOLD
e al massimo UNTREEIFY_THRESHOLD = 6
riconvertirete un albero bilanciato in un elenco di voci collegato. Java 8 SRC , stackpost
« Raccolta iterazione, Fail-Fast e Fail-Safe
+--------------------+-----------+-------------+
| | Iterator | Enumeration |
+--------------------+-----------+-------------+
| Hashtable | fail-fast | safe |
+--------------------+-----------+-------------+
| HashMap | fail-fast | fail-fast |
+--------------------+-----------+-------------+
| ConcurrentHashMap | safe | safe |
+--------------------+-----------+-------------+
Iterator
è di natura fallimentare. ovvero genera ConcurrentModificationException se una raccolta viene modificata durante l'iterazione diversa dal proprio metodo remove (). Dove com'è a Enumeration
prova di errore in natura. Non genera eccezioni se una raccolta viene modificata durante l'iterazione.
Secondo Java API Docs, Iterator è sempre preferito rispetto all'enumerazione.
NOTA: la funzionalità dell'interfaccia di enumerazione è duplicata dall'interfaccia Iterator. Inoltre, Iterator aggiunge un'operazione di rimozione facoltativa e ha nomi di metodo più brevi. Le nuove implementazioni dovrebbero prendere in considerazione l'utilizzo di Iterator rispetto all'enumerazione.
In Java 5 è stata introdotta l'interfaccia ConcurrentMap : ConcurrentHashMap
- ConcurrentMap
un'implementazione altamente concorrenziale e ad alte prestazioni supportata da una tabella hash. Questa implementazione non si blocca mai durante l'esecuzione di recuperi e consente al client di selezionare il livello di concorrenza per gli aggiornamenti. È inteso come un sostituto drop-in per Hashtable
: oltre all'implementazione ConcurrentMap
, supporta tutti i metodi "legacy" peculiari Hashtable
.
Il HashMapEntry
valore di ogni s è volatile , garantendo così una consistenza a grana fine per le modifiche contestate e le letture successive; ogni lettura riflette l'aggiornamento completato più di recente
Iteratori ed enumerazioni sono Fail Safe - riflettendo lo stato ad un certo punto dalla creazione dell'iteratore / enumerazione; ciò consente letture e modifiche simultanee a scapito della coerenza ridotta. Non generano ConcurrentModificationException. Tuttavia, gli iteratori sono progettati per essere utilizzati da un solo thread alla volta.
Come Hashtable
ma diversamente HashMap
, questa classe non consente l'utilizzo di null come chiave o valore.
public static void main(String[] args) {
//HashMap<String, Integer> hash = new HashMap<String, Integer>();
Hashtable<String, Integer> hash = new Hashtable<String, Integer>();
//ConcurrentHashMap<String, Integer> hash = new ConcurrentHashMap<>();
new Thread() {
@Override public void run() {
try {
for (int i = 10; i < 20; i++) {
sleepThread(1);
System.out.println("T1 :- Key"+i);
hash.put("Key"+i, i);
}
System.out.println( System.identityHashCode( hash ) );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}.start();
new Thread() {
@Override public void run() {
try {
sleepThread(5);
// ConcurrentHashMap traverse using Iterator, Enumeration is Fail-Safe.
// Hashtable traverse using Enumeration is Fail-Safe, Iterator is Fail-Fast.
for (Enumeration<String> e = hash.keys(); e.hasMoreElements(); ) {
sleepThread(1);
System.out.println("T2 : "+ e.nextElement());
}
// HashMap traverse using Iterator, Enumeration is Fail-Fast.
/*
for (Iterator< Entry<String, Integer> > it = hash.entrySet().iterator(); it.hasNext(); ) {
sleepThread(1);
System.out.println("T2 : "+ it.next());
// ConcurrentModificationException at java.util.Hashtable$Enumerator.next
}
*/
/*
Set< Entry<String, Integer> > entrySet = hash.entrySet();
Iterator< Entry<String, Integer> > it = entrySet.iterator();
Enumeration<Entry<String, Integer>> entryEnumeration = Collections.enumeration( entrySet );
while( entryEnumeration.hasMoreElements() ) {
sleepThread(1);
Entry<String, Integer> nextElement = entryEnumeration.nextElement();
System.out.println("T2 : "+ nextElement.getKey() +" : "+ nextElement.getValue() );
//java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode
// at java.util.HashMap$EntryIterator.next
// at java.util.Collections$3.nextElement
}
*/
} catch ( Exception e ) {
e.printStackTrace();
}
}
}.start();
Map<String, String> unmodifiableMap = Collections.unmodifiableMap( map );
try {
unmodifiableMap.put("key4", "unmodifiableMap");
} catch (java.lang.UnsupportedOperationException e) {
System.err.println("UnsupportedOperationException : "+ e.getMessage() );
}
}
static void sleepThread( int sec ) {
try {
Thread.sleep( 1000 * sec );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
« Null Keys e Null Values
HashMap
consente un massimo di una chiave null e qualsiasi numero di valori null. Dove as Hashtable
non consente nemmeno una singola chiave null e un valore null, se la chiave o il valore null è allora genera NullPointerException. Esempio
« Sincronizzato, thread-safe
Hashtable
è sincronizzato internamente. Pertanto, è molto sicuro da usare Hashtable
in applicazioni multi-thread. Dove as HashMap
non è sincronizzato internamente. Pertanto, non è sicuro utilizzare HashMap
in applicazioni multi-thread senza sincronizzazione esterna. Puoi sincronizzare esternamente HashMap
usando il Collections.synchronizedMap()
metodo.
« Prestazioni
Come Hashtable
sincronizzato internamente, questo rende Hashtable
leggermente più lento di HashMap
.
@Vedere