Java集合-Map_java集合map的比较key的方法

createh51个月前 (02-11)技术教程11

Map(java.util.Map)接口,代表着key和value间的映射,更具体地说,Java映射可以存储键和值对,一旦存储在地图中,以后就可以只使用键来查找值。Map接口不是Collection 的子接口,因此,它的行为与其他Collection 类型稍有不同。

Map的实现

既然Map是个接口,因此初始化时需要使用她的具体实现,Map包括以下实现类:

  • java.util.HashMap
  • java.util.Hashtable
  • java.util.EnumMap
  • java.util.IdentityHashMap
  • java.util.LinkedHashMap
  • java.util.Properties
  • java.util.TreeMap
  • java.util.WeakHashMap

根据我的经验来最常用的是HashMap和TreeMap。在迭代映射时,每一个Map实现的行为都与元素的顺序以及在映射中插入和访问元素所需的时间(big O表示法)稍有不同。

HashMap映射键值,但是不保证存储在map的内部顺序。

TreeMap 同样映射键值,但是可以保证key或者value的顺序。

如不需要元素的顺序的话可以使用HashMap,因为HashMap速度很快,否则的话使用TreeMap。

创建Map

创建新的Map必须使用它的实现之一:

Map mapA = new HashMap();
?
Map mapB = new TreeMap();

Map的泛型

默认可以往Map里面添加任何对象,但是用了泛型后,可以限制其类型:

Map map =
??? new HashMap();

这个Mao只能接受String类型的Key和MyObject 实例的value,同时访问和迭代它们不需要强制类型转换:

for(MyObject anObject : map.values()){
?? //do someting with anObject...
}
?
for(String key : map.keySet()){
?? MyObject value = map.get(key);
?? //do something to value
}

如果指定要往Map中插入的对象,则定义时考虑使用泛型,这样避免了往Map中添加错误的对象。

Map中插入元素

可以通过put()方法添加元素:

Map map = new HashMap<>();
?
map.put("key1", "element 1");
map.put("key2", "element 2");
map.put("key3", "element 3");

调用了三次put()方法添加键值,可以通过键key获取对应的值value。

只能插入对象

Map的键值只能插入对象,如果将原始值(例如int、double等)作为键或值传递给映射,则在作为参数传递之前,原始值将自动装箱,下面是自动装箱的例子:

map.put("key", 123);

上面的例子中,value的值添加了原始值int,java对自动装箱变成Integer实例,因为put()方法需要的是对象实例。

后续插入相同的键key

一个key在Map中只能出现一次,这意味着Map只能存在同一对键值对,也就是同一个Map中只能存在一个“key1“的key值。如果多次调用put()方法插入相同的值,那么之前的值会被覆盖。

Null值的Key

可以用null作为key放到Map中:

Map map = new HashMap();
?
map.put(null, "value for null key");

可以通过get()方法获取key为null的值:

Map map = new HashMap<>();
?
String value = map.get(null);

Null值得Values

Value得值同样允许为null:

map.put("D", null);

请记住,稍后使用该键调用get()时将得到一个null值-因此这将返回null:

Object value = map.get("D");

代码执行后value变量的值将是null。

把另外一个Map中的所有元素插入Map

Map接口中有一个putAll()方法,可以将另外一个Map实例中的所有键值拷贝到当前Map中,实际上就是两个Map的合集,下面是代码:

Map mapA = new HashMap<>();
mapA.put("key1", "value1");
mapA.put("key2", "value2");
?
Map mapB = new HashMap<>();
mapB.putAll(mapA);

执行完代码后,mapB 将包含mapA中所有的键值对,条目的复制只有一种方式。调用 mapB.putAll(mapA) 只会将mapA中的元素添加到mapB中,而不会将mapB中的元素添加到mapA中。

从Map中获取元素

可以通过Map的get()方法获取指定key值的元素值:

Map map = new HashMap();
?
map.put("key1", "value 1");
?
String element1 = (String) map.get("key1");

注意get()方法返回的是 Object,所以需要强制转换成String (因为知道是String)。下面是使用泛型的用法:

Map map = new HashMap<>();
?
map.put("key1", "value 1");
?
String element1 = map.get("key1");

获取默认值

Map接口有个 getOrDefault()方法,这个方法如果Map中没有对应key的值则返回一个默认值:

Map map = new HashMap<>();
?
map.put("A", "1");
map.put("B", "2");
map.put("C", "3");
?
String value = map.getOrDefault("E", "default value");

这个例子Map创建,并且存储了key值为 A, B 和 C。然后调用了Map的getOrDefault()方法,参数为String类型的 E的key值,因此会返回默认值,因为Map中不包含E这个key, 默认值是作为第二个参数传入的。

检查Map是否包含某个Key

可以使用Map的 containsKey()方法,检查是否包含某个key:

boolean hasKey = map.containsKey("123");

代码执行后,hasKey变量的值是true,我们map中包含key”123”,否则返回false。

检查是否包含某个Value

Map接口中同样有个containsValue() 方法可以检查是否包含某个value:

boolean hasValue = map.containsValue("value 1");

执行完代码后,如果map中有value为“value 1“的值则hasValue返回true,否则返回false。

根据Keys迭代Map

有下面几种方法可以迭代Map的key:

  • 通过key 的Iterator
  • 通过for-each循环
  • 通过Stream

通过Key的Iterator

通过Map 的 keySet()迭代所有的key:

Iterator iterator = map.keySet().iterator();
?
while(iterator.hasNext(){
? Object key?? = iterator.next();
? Object value = map.get(key);
}

上面例子,key 的Iterator返回Map中的每个key,可以调用next()方法,一个个的返回。获取到了key就可以通过get()方法获取到对应的值。下面看看使用泛型:

Map map = new HashMap<>();
?
Iterator iterator = map.keySet().iterator();
?
while(iterator.hasNext(){
? String key?? = iterator.next();
? String value = map.get(key);
}

注意泛型同样使用了map.keySet().iterator()方法。

通过Key 的For-Each循环

Java 5以后可以使用for-each循环迭代 key :

for(Object key : map.keySet()) {
??? Object value = map.get(key);
}

上面代码的效果与前一节中显示的代码非常相似,如果使用了泛型,可以在for-each循环内使用类型,不需要强制转换:

Map map = new HashMap<>();
?
for(String key : map.keySet()) {
??? String value = map.get(key);
}

通过Key的Stream

Java 8以后可以使用Java Stream迭代Map的keys, Stream 接口是 Java Stream API 已不是,首先需要从key的Sey中获取Stream:

Map map = new HashMap<>();
?
map.put("one", "first");
map.put("two", "second");
map.put("three", "third");
?
Stream stream = map.keySet().stream();
stream.forEach((value) -> {
??? System.out.println(value);
});??? 

迭代Map的Values

同样可以迭代Map的Values,首先通过values()获取 Collection,然后迭代Collection,有下面几种方法:

  • 通过Iterator
  • 通过for-each 循环
  • 通过Stream

通过Value的Iterator

首先获取values的Set中Iterator 实例:

Map map = new HashMap<>();
?
Iterator iterator = map.values().iterator();
?
while(iterator.hasNext()) {
??? String nextValue? iterator.next();
}

由于一个集合是无序的,所以不能保证值集中的值的迭代顺序,但是如果是TreeSet则可以控制顺序。

使用Value 的For-Each循环

第二种方法是通过for-each循环:

Map map = new HashMap<>();
?
for(String value : map.values()){
??? System.out.println(value);
}

通过Value的 Stream

第三种方法是使用Java Stream API,首先通过Map获取value的Set,然后再获取 Stream:

Map map = new HashMap<>();
?
map.put("one", "first");
map.put("two", "second");
map.put("three", "third");
?
Stream stream = map.values().stream();
stream.forEach((value) -> {
??? System.out.println(value);
});
?

迭代Map的Entries

同样可以迭代Map中的所有entries,通过entries意味着键值对key + value ,一个entry 同时包含了key 和value ,之前我们只是迭代了单个key或者value,现在我们同时迭代key和value,有下面两种方式:

  • 通过Entry 的Iterator
  • 通过for-each循环

通过Entry的 Iterator

第一种方式是通过从Map中的entry的Set中获取entry的 Iterator :

Set> entries = map.entrySet();
?
Iterator> iterator =
??? entries.iterator();
?
while(iterator.hasNext()) {
??? Map.Entry entry = iterator.next();
??? String key?? = entry.getKey();
??? String value = entry.getValue();
}

注意这么从Map.Entry 中获取key和 value。

通过Entry的 For-Each循环

第二种方法就是使用for-each循环:

for(Map.Entry entry : map.entrySet()){
??? String key = entry.getKey();
??? String value = entry.getValue();
}

从Map中移除Entries

可以使用(Object key)方法移除Entries,因此,可以移除与键匹配的(key,value)对:

map.remove("key1");

执行完代码后,map中不再包含key1的键值对。

移除所有Entries

可以通过Map的clear()方法移除所有元素:

map.clear();

替换Map中的Entry、

可以通过Map 的 replace()方法替换其中的元素,如果Map中不存在此key的值,则不会做任何事,则有key存在才会替换,和put()方法的工作原理不一样:

Map map = new HashMap<>();
?
map.replace("key", "val2"); //no "key" entry, no replace
?
map.put("key", "val1");???? //now contains "key" entry
?
map.replace("key", "val2"); //now "key" entry replaced

执行完代码后key对应的值是val2。

获取Map中Entries的大小

可以通过 Map 的size() 方法获取Map的 entries数量:

int entryCount = map.size();

检查Map是否是空

Map接口中有一个专门的方法isEmpty() 检查Map是否是空,如果是空返回true否则返回false。

参考:
http://tutorials.jenkov.com/java-collections/map.html

http://tutorials.jenkov.com/java-functional-programming/streams.html

相关文章

整型数据类型有哪些?有哪些表现形式?

整型用于表示没有小数部分的数值,它允许是负数。整型的范围与运行 Java 代码的机器无关,这正是 Java 程序具有很强移植能力的原因之一。与此相反,C 和 C++程序需要针对不同的处理器选择最有效的...

Java中的数据类型_java里面的数据类型

4.数据类型4.1 java中的数据类型分为两大类:基本数据类型和引用类型。基本数据类型:数值型 byte[1],short[2],int[4],long[8]浮点型 float[4],double[...

六种java的多线程设计模式详解和代码举例

java的多线程处理,有哪些模式可以使用呢,如何使用呢。本文列举了六种多线程设计模式供大家参考。1.生产者-消费者模式设计理念:生产者-消费者模式通过协调两个线程(生产者和消费者)来处理数据,生产者生...

造轮子的时候不敢用不会用泛型?那你看这篇就够了!

阅读本文解决什么问题?解决许多java开发 或者android开发 在平时写一些基础架构,或者是造一些轮子的时候不敢用泛型,用不好泛型的问题。 甚至有些人使用泛型的时候报错都只会用idea提示的方法来...

Java 7种类类型,新手必备_java的类型

今天给老婆整理了一下Java的几种类类型,希望她能对类的基本情况增加一些了解。1、接口(interface)接口是一个定义了方法规范(返回值、方法名、参数)的类,一般情况下不实现具体逻辑(在JDK1....

面试官:JDK中都用了哪些设计模式?

设计模式是前辈们经过实践验证总结的解决方案,帮助我们构建出更具可维护性、可扩展性和可读性的代码。当然,在面试的过程中,也会或多或少的被问到。那么今天,我们就来看一道设计模式中的常见面试问题:JDK 中...