有关Java Map的9大问题

通常,Map是由一组键值对组成的数据结构,每个键只能在映射中出现一次。这篇文章总结了有关如何使用Java Map及其实现的类的前9个常见问题解答。为了简单起见,我将在示例中使用泛型。因此,我将只写Map而不是具体的Map。但是,您始终可以假设K和V都是可比较的,这意味着K extends Comparable和V extends Comparable。在这里插入图片描述

1.将map转换为列表

在Java中,Map接口提供了三个集合视图:键集,值集和键值集。所有这些都可以使用构造函数或addAll()方法转换为List。以下代码段显示了如何从map构造ArrayList。
//键列表列表键列表= 新 的ArrayList (map。中的keySet ()); //值列表列表值列表= 新 的ArrayList (map。值()); //键值列表列表 entryList = 新 的ArrayList (map。的entrySet ());

2.遍历map

遍历每对键值是遍历map的最基本操作。在Java中,这样的对存储在名为Map.Entry的映射条目中。map。entrySet()返回键值集,因此遍历map每个条目的最有效方法是
对于(入口进入:。map的entrySet ()) {
//获取密钥
K键=项。getKey ();
//获取值
V值=条目。getValue (); }
也可以使用Iterator,尤其是在JDK 1.5之前
迭代器 itr =map。entrySet ()。迭代器(); 而( ITR。hasNext ()) {
条目条目= ITR。next ();
//获取密钥
K key = entry。getKey ();
//获取值
V值=条目。getValue (); }

3.在按键上对map排序

在按键上对map进行排序是另一种常见的操作。一种方法是将Map.Entry放入列表中,并使用对值进行排序的比较器对其进行排序。
列表列表= 新的 ArrayList (map。entrySet ()); 集合。排序(列表,新的 比较器() {

@Override
public int compare (条目e1,条目e2 ) {
返回 e1。getKey ()。的compareTo ( E2。信息getKey ());
}
} );
另一种方法是使用SortedMap,它进一步提供了其键的总排序。因此,所有密钥必须要么实现Comparable要么被比较器接受。
一个实现类的SortedMap的是TreeMap的。它的构造函数可以接受比较器。以下代码显示了如何将普通map转换为排序的map。
SortedMap sortedMap = new TreeMap (new Comparator () {

@Override
public int compare ( K k1,K k2 ) {
返回 k1。compareTo ( k2 );
}
} );
sortedMap。putAll (map);

4.根据值对map排序

将map放入列表并对其进行排序也适用于这种情况,但是我们需要比较Entry。这次是getValue()。下面的代码与以前几乎相同。
列表列表= 新的 ArrayList (map。entrySet ()); 集合。排序(列表,新的 比较器() {

@Override
public int compare (条目e1,条目e2 ) {
返回 e1。getValue ()。的compareTo ( E2。的getValue ());
}
} );
我们仍然可以对此问题使用排序映射,但前提是这些值也必须是唯一的。在这种情况下,您可以将“键=值”对反转为“值=键”。这个解决方案有很强的局限性,因此我不推荐这样做。

5.初始化静态/不可变映射

当您希望map保持不变时,将其复制到不可变map中是一种好习惯。这种防御性编程技术不仅可以帮助您创建安全使用的线程映射,而且还可以安全创建线程映射。
要初始化静态/不可变映射,我们可以使用静态初始化器(如下所示)。该代码的问题在于,尽管map声明为static final,但我们仍然可以在初始化后像一样操作它Test.map.put(3,“three”);。因此,它并不是真正不变的。要使用静态初始化程序创建一个不变的映射,我们需要一个额外的匿名类,并在初始化的最后一步将其复制到一个不可修改的映射中。请参阅第二段代码。然后,如果运行,将抛出UnsupportedOperationExceptionTest.map.put(3,“three”);。
公开 课测试{

私人 静态 最终 mapmap;
静态 {
map = new HashMap ();
map。把(1,“一个” );
map。放(2,“两个” );
} } 公共 类测试{

私人 静态 最终 mapmap;
静态 {
Map aMap = new HashMap ();
一张map。把(1,“一个” );
一张map。放(2,“两个” );
map = 收藏集。unmodifiableMap ( aMap );
} }
Guava库还支持引入静态和不可变集合的不同方法。要了解有关Guava不可变集合实用程序的好处的更多信息,请参阅《 Guava用户指南》中介绍的不可变集合。

6. HashMap,TreeMap和Hashtable之间的区别

Java中有三个主要的Map接口实现:HashMap,TreeMap和Hashtable。最重要的区别包括:
1.迭代的顺序。HashMap和Hashtable不保证map的顺序。特别是,它们不能保证顺序会随着时间的推移保持恒定。但是TreeMap将根据键的“自然顺序”或由比较器来迭代整个条目。
2.键值权限。HashMap允许使用null键和null值(仅允许使用一个null键,因为不允许两个键相同)。哈希表不允许使用空键或空值。如果TreeMap使用自然顺序或其比较器不允许使用null键,则将引发异常。
3.已同步。仅哈希表已同步,其他哈希表未同步。因此,“如果不需要线程安全的实现,建议使用HashMap代替Hashtable。”
比较完整的比较是
| HashMap | 哈希表| 树状图


迭代顺序| 没有 没有 是
空键值| 是-是| 没有- 不可以
同步 没有 是的 没有
时间表现| O(1)| O(1)| O(log n)
实施| 水桶| 水桶| 红黑树
阅读有关HashMap,TreeMap,Hashtable,LinkedHashMap的更多信息。

7.具有反向视图/查找的map

有时,我们需要一组键-键对,这意味着映射的值以及键(一对一映射)都是唯一的。该约束使得能够创建map的“反向查找/视图”。因此,我们可以通过键的值查找键。这种数据结构称为双向映射,不幸的是JDK不支持。
Apache Common Collections和Guava都提供了双向map的实现,分别称为BidiMap和BiMap。两者都强制要求键和值之间存在1:1关系的限制。

8.map的浅副本

Java的大多数map实现(如果不是全部)都提供另一个map副本的构造函数。但是复制过程不同步。这意味着当一个线程复制map时,另一线程可以在结构上进行修改。为了[防止意外的非同步副本,应该使用Collections。提前进行syncedMap()。
map copyMap = Collections。同步map(map);
浅表复制的另一种有趣方式是使用clone()方法。但是,Java收集框架的设计者Josh Bloch甚至不建议这样做。他在关于“ 复制构造函数与克隆 ” 的对话中说
我经常在具体类上提供公共克隆方法,因为人们期望这样做。……可克隆性被打破是很遗憾的,但是它确实发生了。…可克隆性是一个薄弱环节,我认为人们应该意识到它的局限性。
因此,我什至不会告诉您如何使用clone()方法复制map。

9.创建一个空的map

如果map是不可变的,请使用
map = 收藏集。emptyMap ();
否则,请使用任何实现。例如
map = new HashMap ();
最后,开发这么多年我也总结了一套学习Java的资料与面试题,如果你在技术上面想提升自己的话,可以关注我,私信发送领取资料或者在评论区留下自己的联系方式,有时间记得帮我点下转发让跟多的人看到哦。在这里插入图片描述

发布了38 篇原创文章 · 获赞 8 · 访问量 2693

猜你喜欢

转载自blog.csdn.net/zhaozihao594/article/details/103990978