大家好,我是G探险者。
今天主要介绍一下MultiValueMap和HashMap的区别。
事情起因是这样的,在我们项目code review的时候,客户方提了一个问题,说,你们在用restTemplate进行远程调用的时候,为啥使用MultiValueMap来传递参数,而不用HashMap。
这有啥区别么?
当时没有给出专业的解答。事后我就好好查询了一番。
从以下几个方面来阐述。
1. MultiValueMap 和 HashMap的区别?
MultiValueMap
和HashMap
在数据结构上有一些差异,这导致了它们对待键值对的方式不同,从而使得MultiValueMap
可以支持一个键对应多个值,而HashMap
则不支持。
MultiValueMap:
MultiValueMap
是Spring Framework中的接口,它的实现类通常是LinkedMultiValueMap
。它的实现方式是每个键可以映射到一个值的列表,而不是单个值。这样就允许一个键拥有多个值。
HashMap:
HashMap
在jdk<=1.7是基于数组+链表 在jdk>=1.8是数据+链表+红黑树,每个键值对映射到一个唯一的键上。因此,当你向HashMap
中添加一个已经存在的键时,新值会覆盖旧值,而不是追加在旧值的后面。这就是为什么HashMap
不支持一个键对应多个值的原因。
对比:
- 存储方式 :
MultiValueMap
采用列表来存储值,一个键可以对应多个值;而HashMap
每个键只能对应一个值,不支持多值。 - 数据结构 :
MultiValueMap
内部使用了链表或者类似结构,以便存储多个值;HashMap
内部使用数组+链表(或者红黑树),每个键对应一个唯一的哈希值。 - 使用场景 :
MultiValueMap
适用于需要存储多个值的情况,比如HTTP请求参数;HashMap
适用于需要唯一键值对的情况,比如建立字典。
下面是一个对比MultiValueMap
和HashMap
的区别的表格:
特性 | MultiValueMap | HashMap |
---|---|---|
数据结构 | 键对应值的列表 | 哈希表 |
是否支持多值 | 是 | 否 |
用途 | 表单数据、HTTP请求参数 | 通用键值对存储 |
处理重复键 | 支持,每个键可以对应多个值 | 后添加的值会覆盖之前的值 |
参数编码 | 无需手动编码,自动处理 | 需要手动进行URL编码 |
框架集成 | Spring框架中常用 | 通用 |
示例代码 | MultiValueMap<String, List<String>> |
HashMap<String, String> |
通过这个表格,可以清晰地了解到MultiValueMap
和HashMap
在数据结构、支持多值、参数编码、框架集成等方面的区别。MultiValueMap
更适用于处理需要支持多值的情况,特别是在Spring框架中;而HashMap
适用于一般的键值对存储。
综上所述,虽然MultiValueMap
和HashMap
都用于存储键值对,但它们的底层数据结构和对键值对的处理方式不同,导致了它们在支持一个键对应多个值这个特性上的差异。
了解了以上、MultiValueMap 和 HashMap在数据结构上的差异,我们再来讨论下面的问题
2. form表单提交的请求类型x-www-form-urlencoded为啥使用MultiValueMap来传递参数更合适?
在使用HttpClient发送x-www-form-urlencoded类型的请求时,通常需要使用MultiValueMap来传递参数,这是因为x-www-form-urlencoded格式要求参数以键值对的形式进行传递,而且在同一个键名下可能存在多个值。MultiValueMap是Spring Framework中的一种数据结构,用于表示键值对,并且支持一个键对应多个值的情况。
总结起来,主要有以下几个原因:
-
多值支持: x-www-form-urlencoded格式要求同一个参数名可以对应多个值,而MultiValueMap正是为了支持这种情况而设计的。在HashMap中,相同的键只能对应一个值,如果需要传递多个值,你可能需要自己手动处理这种情况,而使用MultiValueMap则可以直接支持多值。
-
参数编码: x-www-form-urlencoded格式要求参数需要进行URL编码,以确保特殊字符正确传输。Spring框架中的MultiValueMap会自动处理这种编码,确保参数在传输过程中不会出现问题。如果使用HashMap,你需要自己编写代码来手动进行参数的编码,这样就增加了额外的工作量和复杂度。
-
框架集成: 在Spring框架中,很多API都会接受MultiValueMap类型的参数,因此使用MultiValueMap能够更好地与Spring的其他功能集成。例如,Spring提供了RestTemplate类来发送HTTP请求,该类的一些方法接受MultiValueMap类型的参数,这样你可以直接传递参数而无需进行额外的转换。
综上所述,虽然你可以使用HashMap来传递参数,但是为了更好地符合x-www-form-urlencoded格式的要求,以及在Spring框架中更好地与其他功能集成,推荐使用MultiValueMap来传递参数。
使用MultiValueMap能够更方便地构建这种参数形式,确保参数按照x-www-form-urlencoded格式正确编码。另外,Spring框架提供了一些便捷的方法来构建和处理MultiValueMap,使得参数的处理更加简单和灵活。
下面我分别从代码层面来阐述一下,使用MultiValueMap和使用HashMap进行传值的区别
2.1 使用 MultiValueMap:
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
// 创建 MultiValueMap 对象
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
// 添加参数到 MultiValueMap
params.add("key1", "value1");
params.add("key2", "value2");
params.add("key2", "value3"); // 添加同名参数,支持多值
// 使用 MultiValueMap 发送请求
// 假设 HttpClient 已经实例化为 httpClient
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<String> response = httpClient.exchange(url, HttpMethod.POST, requestEntity, String.class);
2.2 使用 HashMap:
import java.util.HashMap;
import java.util.Map;
// 创建 HashMap 对象
Map<String, String> params = new HashMap<>();
// 添加参数到 HashMap
params.put("key1", "value1");
params.put("key2", "value2");
params.put("key2", "value3"); // 重复的键会覆盖之前的值
// 构建 x-www-form-urlencoded 格式的参数字符串
StringBuilder requestBody = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
if (requestBody.length() > 0) {
requestBody.append("&");
}
requestBody.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
requestBody.append("=");
requestBody.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
// 发送请求
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> requestEntity = new HttpEntity<>(requestBody.toString(), headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
从以上两个示例代码我们可以清楚的看到如下区别:
2.3 区别:
-
多值支持 :
MultiValueMap
支持一个键对应多个值,而HashMap
不支持,需要手动处理。 -
编码处理 :
MultiValueMap
会自动处理参数值的URL编码,而HashMap
需要手动编码。 -
代码复杂度 :使用
MultiValueMap
更简洁,不需要手动构建参数字符串。
总的来说,使用MultiValueMap
更方便、更符合Spring框架的习惯,而使用HashMap
则需要手动处理更多的细节。
如果喜欢的话,请点个关注哦~