Java中的a HashMap
和a有什么区别Hashtable
?
哪个非线程应用程序更有效?
Java HashMap
和Hashtable
Java 之间存在一些差异:
Hashtable
是同步的,而HashMap
不是.这HashMap
对非线程应用程序更有利,因为非同步对象通常比同步对象执行得更好.
Hashtable
不允许null
键或值. HashMap
允许一个null
键和任意数量的null
值.
HashMap的子类之一是LinkedHashMap
,所以如果您想要可预测的迭代顺序(默认情况下是插入顺序),您可以轻松地换出HashMap
for a LinkedHashMap
.如果你使用的话,这并不容易Hashtable
.
由于同步不是你的问题,我建议HashMap
.如果同步成为问题,您也可以查看ConcurrentHashMap
.
请注意,许多答案都表明Hashtable已同步. 在实践中,这很少给你买. 访问器/ mutator方法上的同步将停止两个线程同时添加或从地图中删除,但在现实世界中,您将经常需要额外的同步.
一个非常常见的习语是"检查然后放" - 即在地图中查找条目,如果它尚不存在则添加它.无论您使用Hashtable还是HashMap,这都不是原子操作.
可以通过以下方式获得等效同步的HashMap:
Collections.synchronizedMap(myMap);
但要正确实现此逻辑,您需要额外的表单同步:
synchronized(myMap) { if (!myMap.containsKey("tomato")) myMap.put("tomato", "red"); }
即使迭代Hashtable的条目(或Collections.synchronizedMap获得的HashMap)也不是线程安全的,除非您还通过附加同步保护Map不被修改.
ConcurrentMap接口的实现(例如ConcurrentHashMap)通过包含线程安全的check-then-act语义来解决其中的一些问题,例如:
ConcurrentMap.putIfAbsent(key, value);
Hashtable
被认为是遗留代码.没有什么Hashtable
可以使用HashMap
或推导无法完成HashMap
,所以对于新代码,我认为没有任何理由回到Hashtable
.
在访谈中经常会问这个问题,以检查候选人是否理解收集类的正确用法,并了解可用的替代解决方案.
HashMap类大致相当于Hashtable,除了它是非同步的并且允许空值.(HashMap允许空值作为键和值,而Hashtable不允许空值).
HashMap不保证地图的顺序会随着时间的推移保持不变.
HashMap是非同步的,而Hashtable是同步的.
HashMap中的迭代器是故障安全的,而Hashtable的枚举器不是,如果任何其他线程通过添加或删除除Iterator自己的remove()方法之外的任何元素来修改地图,则抛出ConcurrentModificationException.但这不是一种保证行为,将由JVM尽最大努力完成.
关于一些重要条款的说明
同步意味着只有一个线程可以在一个时间点修改哈希表.基本上,这意味着在哈希表上执行更新之前的任何线程都必须获取对象的锁定,而其他线程将等待锁定被释放.
故障安全与迭代器的上下文相关.如果已在集合对象上创建了迭代器,并且某个其他线程尝试"在结构上"修改集合对象,则将引发并发修改异常.其他线程可以调用"set"方法,因为它不会"在结构上"修改集合.但是,如果在调用"set"之前,集合已在结构上进行了修改,则会抛出"IllegalArgumentException".
结构修改意味着删除或插入可以有效改变地图结构的元素.
HashMap可以同步
HashMap
Map提供了Collection视图,而不是通过Enumeration对象直接支持迭代.集合视图极大地增强了界面的表现力,如本节后面所述.Map允许您迭代键,值或键值对; Hashtable不提供第三种选择.Map提供了一种在迭代过程中删除条目的安全方法; Hashtable没有.最后,Map修复了Hashtable界面中的一个小缺陷.Hashtable有一个名为contains的方法,如果Hashtable包含给定值,则返回true.鉴于其名称,如果Hashtable包含给定键,则您希望此方法返回true,因为该键是Hashtable的主要访问机制.Map接口通过重命名方法containsValue消除了这种混淆的来源.此外,这提高了界面的一致性 - containsValue parallels containsKey.
地图界面
HashMap
:Map
使用哈希代码索引数组的接口的实现.
Hashtable
:嗨,1998年叫.他们想要回收他们的集合API.
说真的,你最好远离Hashtable
完全.对于单线程应用程序,您不需要额外的同步开销.对于高度并发的应用程序,偏执同步可能会导致饥饿,死锁或不必要的垃圾收集暂停.就像Tim Howland指出的那样,你可以ConcurrentHashMap
改用它.
请记住,HashTable
在引入Java Collections Framework(JCF)之前,这是遗留类,后来为了实现Map
接口而进行了改进.那是Vector
和Stack
.
因此,总是在新代码中远离它们,因为在JCF中总有更好的替代方案,正如其他人所指出的那样.
这是您将发现有用的Java集合备忘单.请注意,灰色块包含遗留类HashTable,Vector和Stack.
已发布许多好的答案.我添加了一些新的点并总结了它.
HashMap
和Hashtable
两个用于存储在键和值形式的数据.两者都使用散列技术来存储唯一键.但是下面给出了HashMap和Hashtable类之间的许多差异.
HashMap中
HashMap
是非同步的.它不是线程安全的,如果没有适当的同步代码,就无法在许多线程之间共享.
HashMap
允许一个空键和多个空值.
HashMap
是JDK 1.2中引入的新类.
HashMap
很快
我们可以HashMap
通过调用此代码使其同步
Map m = Collections.synchronizedMap(HashMap);
HashMap
由Iterator遍历.
迭代器HashMap
是快速失败的.
HashMap
继承AbstractMap类.
哈希表
Hashtable
是同步的.它是线程安全的,可以与许多线程共享.
Hashtable
不允许任何null键或值.
Hashtable
是一个遗产类.
Hashtable
是慢的.
Hashtable
是内部同步的,不能不同步.
Hashtable
由Enumerator和Iterator遍历.
枚举器输入Hashtable
不是快速失败的.
Hashtable
继承Dictionary类.
进一步阅读Java中的HashMap和Hashtable有什么区别?
除了izb所说的,HashMap
允许空值,而Hashtable
不是.
另请注意,Hashtable
扩展Dictionary
该类(作为Javadocs状态)已过时并已被Map
接口替换.
看看这张图表.它提供了不同数据结构与HashMap和Hashtable之间的比较.比较准确,清晰,易于理解.
Java Collection Matrix
Hashtable
类似于HashMap
并具有类似的界面.HashMap
除非您需要支持旧应用程序或需要同步,否则建议您使用,因为Hashtables
方法是同步的.因此,在您的情况下,因为您不是多线程,HashMaps
所以最好的选择.
散列表和散列映射之间的另一个关键区别是HashMap中的Iterator是快速失败的,而Hashtable的枚举器不是,如果任何其他Thread通过添加或删除除Iterator自己的remove()方法之外的任何元素而在结构上修改映射,则抛出ConcurrentModificationException.但这不是一种保证行为,将由JVM尽最大努力完成."
我的来源:http://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html
除了这里已经提到的所有其他重要方面,Collections API(例如Map接口)一直在被修改,以符合Java规范的"最新和最好"的补充.
例如,比较Java 5 Map迭代:
for (Elem elem : map.keys()) { elem.doSth(); }
与旧的Hashtable方法相比:
for (Enumeration en = htable.keys(); en.hasMoreElements(); ) { Elem elem = (Elem) en.nextElement(); elem.doSth(); }
在Java 1.8中,我们还承诺能够构建和访问HashMaps,就像在旧的脚本语言中一样:
Mapmap = { "orange" : 12, "apples" : 15 }; map["apples"];
更新:不,他们不会降落在1.8 ...... :(
Project Coin的集合增强功能将在JDK8中进行吗?
HashTable是同步的,如果您在单个线程中使用它,则可以使用HashMap,这是一个不同步的版本.非同步对象通常更具性能.顺便说一下,如果多个线程同时访问HashMap,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步.您可以使用以下方法将未同步的地图包装在同步的地图中:
Map m = Collections.synchronizedMap(new HashMap(...));
HashTable只能包含非空对象作为键或值.HashMap可以包含一个空键和空值.
Map返回的迭代器是快速失败的,如果在创建迭代器之后的任何时候对映射进行结构修改,除了通过迭代器自己的remove方法之外,迭代器将抛出一个ConcurrentModificationException
.因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险.而 Hashtable的键和元素方法返回的枚举并不是快速失败的.
HashTable和HashMap是Java Collections Framework的成员(自Java 2平台v1.2起,HashTable被改进以实现Map接口).
HashTable被认为是遗留代码,如果需要线程安全的高度并发实现,文档建议使用ConcurrentHashMap代替Hashtable.
HashMap不保证返回元素的顺序.对于HashTable,我猜它是一样的,但我不完全确定,我找不到明确说明这一点的资源.
HashMap
并且Hashtable
具有显着的算法差异.之前没有人提到这一点,所以这就是我提出这个问题的原因.HashMap
将构造一个具有两个大小的哈希表,动态增加它,使得你在任何桶中最多有八个元素(冲突),并且会很好地激发一般元素类型的元素.但是,Hashtable
如果你知道自己在做什么,那么实现提供了对哈希的更好和更精细的控制,即你可以使用最接近的质数来修复表大小到你的值域大小,这将导致比HashMap更好的性能,即更少的冲突对于某些情况.
除了在这个问题中广泛讨论的显而易见的差异之外,我认为Hashtable是一个"手动驱动"汽车,你可以更好地控制散列和HashMap作为通常表现良好的"自动驱动"对应物.
Hashtable是同步的,而HashMap则不是.这使得Hashtable比Hashmap慢.
对于非线程应用程序,请使用HashMap,因为它们在功能方面是相同的.
根据这里的信息,我建议使用HashMap.我认为最大的优点是Java会阻止你在迭代它时修改它,除非你通过迭代器完成它.
A Collection
- 有时称为容器 - 只是一个将多个元素组合成一个单元的对象.Collection
s用于存储,检索,操作和传递聚合数据.集合框架W是用于表示和操作集合的统一体系结构.
的HashMap
JDK1.2
和Hashtable JDK1.0
,两者都用来表示一组在表示的对象的
一对.每
对称为Entry
对象.参赛作品的收集是由对象简称HashMap
和Hashtable
.集合中的键必须是唯一的或独特的.[因为它们用于检索特定键的映射值.集合中的值可以重复.]
« 超类,遗产和收藏框架成员
Hashtable是一个引入的遗留类JDK1.0
,它是Dictionary类的子类.从JDK1.2
Hashtable重新设计实现Map接口以构成集合框架的成员.HashMap从一开始就是Java Collection Framework的成员JDK1.2
.HashMap是AbstractMap类的子类.
public class Hashtable extends Dictionary implements Map, Cloneable, Serializable { ... }
public class HashMap extends AbstractMap implements Map, Cloneable, Serializable { ... }
« 初始容量和负载系数
容量是哈希表中的桶数,初始容量只是创建哈希表时的容量.请注意,哈希表是打开的:在" hash
collision
" 的情况下,单个存储桶存储多个条目,必须按顺序搜索.加载因子是在自动增加容量之前允许哈希表获取的完整程度的度量.
HashMap使用默认初始容量(16)和默认加载因子(0.75)构造一个空哈希表.Hashtable在何处使用默认初始容量(11)和加载因子/填充率(0.75)构造空哈希表.
« 哈希冲突情况下的结构修改
HashMap
,Hashtable
在哈希冲突的情况下,它们存储在链表的映射条目.从Java8 forHashMap
if hash bucket超过某个阈值,该桶将从中切换linked list of entries to a balanced tree
.它改善了从O(n)到O(log n)的最坏情况性能.在将列表转换为二叉树时,哈希码用作分支变量.如果同一个存储桶中有两个不同的哈希码,则一个被认为更大,并且位于树的右侧,另一个位于左侧.但是当两个哈希码都相等时,HashMap
假设密钥是可比较的,并比较密钥以确定方向,以便可以维持某个顺序.制作HashMap
可比较的钥匙是一个好习惯.在添加条目时,如果存储桶大小达到TREEIFY_THRESHOLD = 8
将条目的链接列表转换为平衡树,则在删除小于TREEIFY_THRESHOLD
和最多的条目时,UNTREEIFY_THRESHOLD = 6
会将平衡树重新转换为链接的条目列表.Java 8 SRC,stackpost
« 集合视图迭代,失败快速和失败安全
+--------------------+-----------+-------------+
| | Iterator | Enumeration |
+--------------------+-----------+-------------+
| Hashtable | fail-fast | safe |
+--------------------+-----------+-------------+
| HashMap | fail-fast | fail-fast |
+--------------------+-----------+-------------+
| ConcurrentHashMap | safe | safe |
+--------------------+-----------+-------------+
Iterator
是一种快速失败的性质.即如果在迭代时修改集合而不是它自己的remove()方法,则抛出ConcurrentModificationException.凡为Enumeration
是故障安全性的.如果在迭代时修改了集合,则不会抛出任何异常.
根据Java API Docs,Iterator始终优于Enumeration.
注意: Enteration接口的功能由Iterator接口复制.此外,Iterator添加了一个可选的删除操作,并且具有更短的方法名称.新实现应考虑使用Iterator而不是Enumeration.
在Java 5中引入了ConcurrentMap接口:ConcurrentHashMap
- ConcurrentMap
由哈希表支持的高度并发,高性能的实现.执行检索时,此实现永远不会阻塞,并允许客户端选择更新的并发级别.它旨在作为以下内容的替代品Hashtable
:除了实现之外ConcurrentMap
,它还支持所有特有的"遗留"方法Hashtable
.
每个HashMapEntry
s值都是易失性的,从而确保了竞争修改和后续读取的细粒度一致性; 每次阅读都反映了最近完成的更新
迭代器和枚举是失败安全的 - 自迭代器/枚举创建以来某些时候反映状态; 这允许以降低一致性为代价同时进行读取和修改.它们不会抛出ConcurrentModificationException.但是,迭代器设计为一次只能由一个线程使用.
类似Hashtable
但不同HashMap
,这个类不允许空用作键或值.
public static void main(String[] args) {
//HashMap hash = new HashMap();
Hashtable hash = new Hashtable();
//ConcurrentHashMap 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 e = hash.keys(); e.hasMoreElements(); ) {
sleepThread(1);
System.out.println("T2 : "+ e.nextElement());
}
// HashMap traverse using Iterator, Enumeration is Fail-Fast.
/*
for (Iterator< Entry > it = hash.entrySet().iterator(); it.hasNext(); ) {
sleepThread(1);
System.out.println("T2 : "+ it.next());
// ConcurrentModificationException at java.util.Hashtable$Enumerator.next
}
*/
/*
Set< Entry > entrySet = hash.entrySet();
Iterator< Entry > it = entrySet.iterator();
Enumeration> entryEnumeration = Collections.enumeration( entrySet );
while( entryEnumeration.hasMoreElements() ) {
sleepThread(1);
Entry 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 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();
}
}
« 空键和空值
HashMap
允许最多一个空键和任意数量的空值.如果Hashtable
不允许甚至单个null键和null值,如果键或值为null,则抛出NullPointerException.例
« 同步,线程安全
Hashtable
在内部同步.因此,Hashtable
在多线程应用程序中使用它是非常安全的.哪里HashMap
没有内部同步.因此,HashMap
在没有外部同步的多线程应用程序中使用是不安全的.您可以HashMap
使用Collections.synchronizedMap()
方法在外部进行同步.
« 表现
由于Hashtable
在内部同步,这Hashtable
比稍微慢一点HashMap
.
@看到
红黑树是一种自平衡二叉搜索树
HashMap
Java 8中的性能改进
对于线程应用程序,您可以经常使用ConcurrentHashMap - 取决于您的性能要求.
1. Hashmap
并HashTable
存储密钥和值.
2. Hashmap
可以存储一个密钥null
.Hashtable
不能存储null
.
3. HashMap
未同步但Hashtable
已同步.
4. HashMap
可以同步Collection.SyncronizedMap(map)
Map hashmap = new HashMap(); Map map = Collections.SyncronizedMap(hashmap);
除了已经提到的差异,应该指出的是,自从Java 8,HashMap
动态替换每个桶使用树节点(红黑树)的节点(链表),这样,即使高哈希冲突存在,最坏的情况下,当搜索是
O(log(n))对于HashMap
Vs O(n)in Hashtable
.
*上述改进还没有被应用到Hashtable
还没有,但只HashMap
,LinkedHashMap
和ConcurrentHashMap
.
仅供参考,目前,
TREEIFY_THRESHOLD = 8
:如果存储桶包含8个以上的节点,则链表将转换为平衡树.
UNTREEIFY_THRESHOLD = 6
:当桶变得太小(由于删除或调整大小)时,树将转换回链表.
HashTable和HashMaps有5个基本区别.
Maps允许您迭代和检索键,值和两个键值对,其中HashTable没有所有这些功能.
在Hashtable中有一个函数contains(),它使用起来非常混乱.因为contains的含义略有偏差.它意味着包含密钥还是包含值?难以理解.在Maps中我们有ContainsKey()和ContainsValue()函数,它们很容易理解.
在hashmap中,您可以安全地在迭代时删除元素.在哈希表中不可能的地方.
HashTable默认是同步的,因此它可以轻松地与多个线程一起使用.默认情况下,HashMaps不同步,因此只能与单个线程一起使用.但您仍然可以使用Collections util类的synchronizedMap(Map m)函数将HashMap转换为同步.
HashTable不允许使用null键或null值.HashMap允许一个空键和多个空值的位置.
我的小贡献:
首先,也是最显著之间的不同
Hashtable
和HashMap
是,HashMap
是不是线程安全的,同时Hashtable
是一个线程安全的集合.第二个重要的区别是
Hashtable
和HashMap
性能,因为HashMap
它不同步它表现得更好Hashtable
.关于第三个区别
Hashtable
VSHashMap
是Hashtable
已经过时的类,你应该使用ConcurrentHashMap
代替Hashtable
Java编写的.
HashMap:它是java.util包中可用的类,它用于以键和值格式存储元素.
Hashtable:它是一个遗留类,在集合框架中被识别.
HashTable是jdk中的遗留类,不应再使用了.用ConcurrentHashMap替换它的用法.如果您不需要线程安全,请使用HashMap,它不是线程安全但更快并且使用更少的内存.
1)Hashtable是同步的,而hashmap不是.2)另一个区别是HashMap中的迭代器是故障安全的,而Hashtable的枚举器则不是.如果你在迭代时更改地图,你就会知道.
3)HashMap允许空值,而Hashtable则不允许.
HashMap和HashTable
关于HashMap和HashTable的一些重要观点.请阅读以下详细信息.
1)Hashtable和Hashmap实现java.util.Map接口2)Hashmap和Hashtable都是基于散列的集合.并致力于散列.所以这些是HashMap和HashTable的相似之处.
HashMap和HashTable有什么区别?
1)第一个区别是HashMap不是线程安全的,而HashTable是ThreadSafe
2)HashMap更好,因为它不是线程安全的.虽然Hashtable性能明智并不好,因为它是线程安全的.所以多线程不能同时访问Hashtable.
Hashtable:
Hashtable是一种保留键值对值的数据结构.它不允许键和值都为null.NullPointerException
如果添加空值,您将得到一个.它是同步的.所以它带来了它的成本.只有一个线程可以在特定时间访问HashTable.
示例:
import java.util.Map; import java.util.Hashtable; public class TestClass { public static void main(String args[ ]) { Mapstates= new Hashtable (); states.put(1, "INDIA"); states.put(2, "USA"); states.put(3, null); //will throw NullPointerEcxeption at runtime System.out.println(states.get(1)); System.out.println(states.get(2)); // System.out.println(states.get(3)); } }
HashMap的:
HashMap类似于Hashtable,但它也接受键值对.它允许键和值都为null.它的性能更好HashTable
,因为它是unsynchronized
.
例:
import java.util.HashMap; import java.util.Map; public class TestClass { public static void main(String args[ ]) { Mapstates = new HashMap (); states.put(1, "INDIA"); states.put(2, "USA"); states.put(3, null); // Okay states.put(null,"UK"); System.out.println(states.get(1)); System.out.println(states.get(2)); System.out.println(states.get(3)); } }