Java Maps的9个常见问题
一般来说,Map是一种由键值对组成的数据结构,其中键(key)在Map中是不能重复的;
本篇文章总结了9个最常见的问题(关于Java Map及其实现类);
出于简单考虑,在代码例子中我将不使用泛型,因此,我将仅仅写上Map而不是写上Map<K, V>,且Map中的Key和Value都是可以比较的,意味着K和V都实现了Comparable接口;
1.Map转List
在Java中,Map接口提供了三个集合视图,即key set, value set,和key-value set。它们都可以转成List集合,如下代码所示:
// key list
List keyList = new ArrayList(map.keySet());
// value list
List valueList = new ArrayList(map.valueSet());
// key-value list
List entryList = new ArrayList(map.entrySet());
2.迭代遍历Map中的key-value
迭代遍历Map中的键值对是最基本的操作。在Java中,键值对信息存储在Map.Entry类中。通过调用Map.entrySet()方法会返回键值对集合,因此最有效的遍历Map中的键值对如下代码所示:
for(Entry entry: map.entrySet()) {
// get key
K key = entry.getKey();
// get value
V value = entry.getValue();
}
当然,也可以通过迭代器遍历,如下代码:
while(itr.hasNext()) {
Entry entry = itr.next();
// get key
K key = entry.getKey();
// get value
V value = entry.getValue();
}
3.Map中的元素按Key排序
对Map中的元素按key排序是另一个经常使用的操作。有一种方法是将Map中的元素放进List集合,然后通过一个比较器对集合进行排序,如下代码示例:
List list = new ArrayList(map.entrySet());
Collections.sort(list, new Comparator() {
public int compare(Entry e1, Entry e2) {
return e1.getKey().compareTo(e2.getKey());
}
});
}
另一种方法是使用SortedMap,其提供了对Key进行排序的功能;前提是Map中的Key需要实现Comparable接口或者通过构造方法传入比较器;
TreeMap是SortedMap的一个实现类,它的构造方法能够接收一个比较器,以下代码展示了如何将普通Map转成SortedMap:
SortedMap sortedMap = new TreeMap(new Comparator() {
@Override
public int compare(K k1, K k2) {
return k1.compareTo(k2);
}
});
sortedMap.putAll(map);
4.Map中的元素按Value排序
同样可以参考前面的将Map的元素放进List集合然后传入比较器进行排序,不过这次要比较的对象是Entry.getValue()。如下代码所示:
List list = new ArrayList(map.entrySet());
Collections.sort(list, new Comparator() {
@Override
public int compare(Entry e1, Entry e2) {
return e1.getValue().compareTo(e2.getValue());
}
});
对于这个问题,当map中的value都是唯一的情况,我们仍然可以使用sorted map来排序,在这种情况下,你可以将key赋值给value,value赋值给key来实现该功能;但是这种解决方法十分受限,非常不建议使用;
5.初始化一个不可修改的Map
当你想要使用Map来存储一些常量时,将他们存储到一个不可修改的Map是一个好习惯。这种防御性编程技术会帮助你创建一个能安全使用且线程安全的map;
我们可以使用静态代码块来初始化一个静态不可变的map,如下代码:
public class Test {
private static final Map map;
static {
map = new HashMap();
map.put(1, "one");
map.put(2, "two");
}
}
然而以上代码是有问题的,即使map被声明成static final,我们仍然可以操作该map,如Test.map.put(3,"three");因此,这不是不可变的map;
为了创建一个不可变的map,我们需要一个额外的map对象,将它作为入参传入Collections.unmodifiableMap方法中,然后得到一个不可变的Map,如下代码:
public class Test {
private static final Map map;
static {
Map aMap = new HashMap();
aMap.put(1, "one");
aMap.put(2, "two");
map = Collections.unmodifiableMap(aMap);
}
}
此时,当我们运行Test.map.put(3,"three")将抛出UnsupportedOperationException异常;
Google的Guava库支持多种方式创建不可变的Map,想学习的可以参考其官方使用手册;
6.HashMap, TreeMap, 和Hashtable的区别
HashMap, TreeMap, 和Hashtable是Map接口的三个主要实现类,它们之间的主要区别如下:
- 是否有序。HashMap和HashTable不会保证元素的有序性,随着时间推移,元素的顺序可能会发生改变;然而TreeMap是有序的,会根据自然顺序或依据比较器排序;
- key- value限制。HashMap允许key和value为null(key只能有一个为null,因为key不能重复)。HashTable不允许key 或value为null;TreeMap如果使用自然顺序或者比较器不允许key为null,使用null key将抛出异常;另外,在TreeMap中value是可以为null的;
- 是否同步。只有Hashtable是同步的,其它的不是。如果线程安全不在考虑范围的话,强烈建议使用HashTable。
另一个比较完整的比较如下:

它们之间的更多比较信息可参考如下链接:
http://www.programcreek.com/2013/03/hashmap-vs-treemap-vs-hashtable-vs-linkedhashmap/
7.反向查找Map
有时候,我们需要key和value都唯一,这种情况允许我们创建一个双向查找Map,也就是说,可以通过唯一的value去查找唯一的Key,遗憾的是,JDK并不支持该数据结构;
Apache Common Collections 和 Guava 提供了对双向查找Map的支持,被叫做BidiMap和BiMap,它们规定了key和value必须是1对1的关系。
8.Map浅拷贝
大部分Map实现类都提供了构造方法,用于对另外一个Map的复制,但是这个复制操作不是同步的,意味着一个线程在对Map进行复制操作的时候,另一个线程可能会对它结构性的修改(增删该等操作);为了阻止意外的非同步操作,应该事先使用Collections.synchronizedMap()方法去创建一个同步Map,如下:
Map copiedMap = Collections.synchronizedMap(map);
另外一种浅拷贝方法是使用clone()方法,然而它并不被集合框架作者Josh Bloch推荐;他曾在一次访谈中谈到关于”拷贝构造方法VS克隆方法“,他说:
I often provide a public clone method on concrete classes because people expect it. ... It’s a shame that Cloneable is broken, but it happens. ... Cloneable is a weak spot, and I think people should be aware of its limitations.
9.创建一个空Map
如果是不可变Map,使用Collections工具类创建,如下:
map = Collections.emptyMap();
否则,直接new,如下:
map = new HashMap();
译文链接:http://www.programcreek.com/2013/09/top-9-questions-for-java-map/
Java Maps的9个常见问题的更多相关文章
- Java编程最差实践常见问题详细说明(2)转
Java编程最差实践常见问题详细说明(2)转 2012-12-13 13:57:20| 分类: JAVA | 标签:java |举报|字号 订阅 反射使用不当 错误的写法: Java代 ...
- Java编程最差实践常见问题详细说明(1)转
Java编程最差实践常见问题详细说明(1)转 原文地址:http://www.odi.ch/prog/design/newbies.php 每天在写Java程序, 其实里面有一些细节大家可能没 ...
- Java虚拟机详解----JVM常见问题总结
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- Java初学者的30个常见问题
本文回答了30个Java入门级初学者的常见问题. 我可以用%除以一个小数吗? a += b 和 a = a + b 的效果有区别吗? 声明一个数组为什么需要花费大量时间?为什么Java库不用随机piv ...
- 关于Java Collections的几个常见问题
列举几个关于Java Collections的常见问题并给出答案. 1. 什么时候用LinkedList,什么时候用ArrayList? ArrayList是使用数组实现的list,本质上就是数组.A ...
- Java编程中的一些常见问题汇总
转载自 http://macrochen.iteye.com/blog/1393502 每天在写Java程序,其实里面有一些细节大家可能没怎么注意,这不,有人总结了一个我们编程中常见的问题.虽然一般 ...
- Java代码规范和一些常见问题
本文中的代码规范,是Java标准代码规范中的一小部分,在我看来,是最重要的一部分. 理想目标:不需要写注释,不需要和别人介绍,别人就知道你的项目大致是做什么的,每个类大概实现了什么功能. ...
- Java集合中Set的常见问题及用法
在这里演示的案例是衔接Java集合中的List(点击查看)那篇博文的,本节我们学习的Set的用法. Set是Collection的一个重要的子接口,Set中的元素是无序排列的,并且元素不可以重复,被称 ...
- 【JAVA】Math.Round()函数常见问题“四舍5入”
java.lang.Math.Round()使用时候,处理方式整理,方便以后查找 /** * 测试函数 2014-01-10 */ public class TestMath { pu ...
随机推荐
- jQuery使用经验建议
在开发过很多 jQuery 插件以后,我慢慢的摸索出了一套开发jQuery插件比较标准的结构和模式.这样我就可以复制并粘贴大部分的代码结构,只要专注最主要的逻辑代码就行了. 使用相同的设计模式和架构也 ...
- 介绍开源的.net通信框架NetworkComms框架 源码分析(七)ProtobufSerializer
原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是 ...
- 关于Bugzilla WebService接口
参考:http://www.bugzilla.org/docs/3.2/en/html/api/Bugzilla/WebService.html http://www.bugzilla.org/doc ...
- Scalaz(1)- 基础篇:隐式转换解析策略-Implicit resolution
在正式进入scalaz讨论前我们需要理顺一些基础的scalaz结构组成概念和技巧.scalaz是由即兴多态(ad-hoc polymorphism)类型(typeclass)组成.scalaz typ ...
- Atitit. 获取cpu占有率的 java c# .net php node.js的实现
Atitit. 获取cpu占有率的 java c# .net php node.js的实现 通过wmic接口获取cpu占有率 C:\Users\Administrator.ATTILAXPC188&g ...
- Verilog学习笔记简单功能实现(七)...............接口设计(并行输入串行输出)
利用状态机实现比较复杂的接口设计: 这是一个将并行数据转换为串行输出的变换器,利用双向总线输出.这是由EEPROM读写器的缩减得到的,首先对I2C总线特征介绍: I2C总线(inter integra ...
- opencart 后台导航菜单添加步骤
1,找到在catalog\language\english\common\header.php // Text$_['text_affiliate'] = 'Affiliates';$_['text_ ...
- 请使用java来构造和遍历二叉树?
[分析] 二叉树的结构:根节点.左子树.右子树.其中左子树的值必须小于根节点,右子树的值必须大于根节点.构造这种树结构,就是创建一个类,并提供一个方法,当给定一个值时,它能够自动创建节点并自动挂到二叉 ...
- go语言 匿名变量
我们在使用传统的强类型语言编程时,经常会出现这种情况,即在调用函数时为了获取一个值,却因为该函数返回多个值而不得不定义一堆没用的变量.在Go中这种情况可以通过结合使用多重返回和匿名变量来避免这种丑陋的 ...
- [deviceone开发]-企业OA项目开源分享
一.简介 是一个真实的企业OA项目改造的开源项目,几乎涵盖了所有常用的组件,包括环信实现在线聊天等功能,类似微信的朋友圈功能,自定义的智能搜索等,而且这个是真实的通过Http链接后台web服务,里面很 ...