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。

目录
相关文章
|
2月前
|
安全 Java 容器
【Java集合类面试二十七】、谈谈CopyOnWriteArrayList的原理
CopyOnWriteArrayList是一种线程安全的ArrayList,通过在写操作时复制新数组来保证线程安全,适用于读多写少的场景,但可能因内存占用和无法保证实时性而有性能问题。
|
2月前
|
Java
【Java集合类面试二十八】、说一说TreeSet和HashSet的区别
HashSet基于哈希表实现,无序且可以有一个null元素;TreeSet基于红黑树实现,支持排序,不允许null元素。
|
2月前
|
Java
【Java集合类面试二十六】、介绍一下ArrayList的数据结构?
ArrayList是基于可动态扩展的数组实现的,支持快速随机访问,但在插入和删除操作时可能需要数组复制而性能较差。
|
19天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
22天前
|
Java C# Swift
Java Stream中peek和map不为人知的秘密
本文通过一个Java Stream中的示例,探讨了`peek`方法在流式处理中的应用及其潜在问题。首先介绍了`peek`的基本定义与使用,并通过代码展示了其如何在流中对每个元素进行操作而不返回结果。接着讨论了`peek`作为中间操作的懒执行特性,强调了如果没有终端操作则不会执行的问题。文章指出,在某些情况下使用`peek`可能比`map`更简洁,但也需注意其懒执行带来的影响。
Java Stream中peek和map不为人知的秘密
|
7天前
|
Go 定位技术 索引
Go 语言Map(集合) | 19
Go 语言Map(集合) | 19
|
6天前
|
存储 前端开发 API
ES6的Set和Map你都知道吗?一文了解集合和字典在前端中的应用
该文章详细介绍了ES6中Set和Map数据结构的特性和使用方法,并探讨了它们在前端开发中的具体应用,包括如何利用这些数据结构来解决常见的编程问题。
ES6的Set和Map你都知道吗?一文了解集合和字典在前端中的应用
|
8天前
|
存储 安全 Java
Java 常用集合分类
Java 常用集合分类
13 2
|
2月前
|
Java
用JAVA架建List集合为树形结构的代码方法
这段代码定义了一个表示树形结构的 `Node` 类和一个用于构建树形结构的 `TreeController`。`Node` 类包含基本属性如 `id`、`pid`、`name` 和 `type`,以及子节点列表 `children`。`TreeController` 包含初始化节点列表并将其转换为树形结构的方法。通过过滤和分组操作实现树形结构的构建。详情可见:[代码示例链接1](http://www.zidongmutanji.com/zsjx/43551.html),[代码效果参考链接2](https://www.257342.com/sitemap/post.html)。
31 5
|
2月前
|
存储 Java 程序员
Java中的集合框架:从入门到精通
【8月更文挑战第30天】在Java的世界里,集合框架是一块基石,它不仅承载着数据的存储和操作,还体现了面向对象编程的精髓。本篇文章将带你遨游Java集合框架的海洋,从基础概念到高级应用,一步步揭示它的奥秘。你将学会如何选择合适的集合类型,掌握集合的遍历技巧,以及理解集合框架背后的设计哲学。让我们一起探索这个强大工具,解锁数据结构的新视角。
下一篇
无影云桌面