Java集合-Map

简介: Java集合-Map

846b1e804993c4ece39e4a0ffa99e472.jpg

Java集合-Map

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<String, MyObject> map =
    new HashMap<String, MyObject>();

这个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<String, String> 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<String, String> 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<String, String> mapA = new HashMap<>();
mapA.put("key1", "value1");
mapA.put("key2", "value2");
Map<String, String> 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<String, String> map = new HashMap<>();
map.put("key1", "value 1");
String element1 = map.get("key1");


获取默认值

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

Map<String, String> 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<String, String> map = new HashMap<>();
Iterator<String> 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<String, String> 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<String, String> map = new HashMap<>();
map.put("one", "first");
map.put("two", "second");
map.put("three", "third");
Stream<String> 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<String, String> map = new HashMap<>();
Iterator<String> iterator = map.values().iterator();
while(iterator.hasNext()) {
    String nextValue  iterator.next();
}

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


使用Value 的For-Each循环

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

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


通过Value的 Stream

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

Map<String, String> map = new HashMap<>();
map.put("one", "first");
map.put("two", "second");
map.put("three", "third");
Stream<String> 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<Map.Entry<String, String>> entries = map.entrySet();
Iterator<Map.Entry<String, String>> iterator =
    entries.iterator();
while(iterator.hasNext()) {
    Map.Entry<String, String> entry = iterator.next();
    String key   = entry.getKey();
    String value = entry.getValue();
}

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


通过Entry的 For-Each循环

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

for(Map.Entry<String, String> 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。

目录
相关文章
|
25天前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第17天】本文详细介绍了Java编程中Map的使用,涵盖Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的并发处理和性能优化技巧,适合初学者和进阶者学习。
39 3
|
25天前
|
存储 Java API
深入剖析Java Map:不只是存储数据,更是设计艺术的体现!
【10月更文挑战第17天】在Java编程中,Map是一种重要的数据结构,用于存储键值对,并展现了设计艺术的精髓。本文深入剖析了Map的设计原理和使用技巧,包括基本概念、设计艺术(如哈希表与红黑树的空间时间权衡)、以及使用技巧(如选择合适的实现类、避免空指针异常等),帮助读者更好地理解和应用Map。
79 3
|
25天前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
52 2
|
25天前
|
存储 Java
告别混乱!用Java Map优雅管理你的数据结构
【10月更文挑战第17天】在软件开发中,随着项目复杂度增加,数据结构的组织和管理至关重要。Java中的Map接口提供了一种优雅的解决方案,帮助我们高效、清晰地管理数据。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,有效提升了代码质量和维护性。
80 2
|
6天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
14 2
|
6天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
11天前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
11天前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
11天前
|
Java 开发者
|
15天前
|
存储 Java API
Java交换map的key和value值
通过本文介绍的几种方法,可以在Java中实现Map键值对的交换。每种方法都有其优缺点,具体选择哪种方法应根据实际需求和场景决定。对于简单的键值对交换,可以使用简单遍历法或Java 8的Stream API;对于需要处理值不唯一的情况,可以使用集合存储或Guava的Multimap。希望本文对您理解和实现Java中的Map键值对交换有所帮助。
19 1