Java 8 :List 转 Map 之 Collectors.toMap()

【前言】

在很多编码时候,我们需要将我们的 List 对象集合,转成为简单的 Map 集合,从而方便很多后续操作。

比如:我们现在有一个用户类 User 如下:

public class User {

	// 用户ID
	private long id;
	
	// 用户名称
	private String name;
	
	// 相关constrator,getter,setter,toString()方法已省略
}

那么,我们可以简单的初始化得到一个 List<User> 的数组,如下所示:

List<User> users = Arrays.asList(
		new User(101, "Jack"), 
		new User(102, "Kreas"), 
		new User(103, "Marry"),
		new User(104, "Timi"),
		new User(105, "Alice"));

如果我们现在需要在该 List 集合中找出 id = 102,id =104 这两个用户的话。

我们也许会如下这么做:

运行程序得到结果为:

当然,这么做是可以的,但这样代码可能会略显臃肿,

既然我们以 id 的方式去查找,何不妨把 List 转成 以 id 为键,对象为值的方式存于Map中。

这样操作起来就会显得更加的巧便:

【2】引入 Collectors.toMap()

在上面的示例代码中,我们将list通过遍历,将它转化为了一个map。

然而在 Java8 中,list 转 map 可以不用如此,我们可以利用 Java 8 stream 特性对集合进行操作,最后采用 Collectors.toMap() 将List 转为 Map。

比如上面的写法可以等价于:

他的结果和上面也是一致的:

这样,我们的代码看起来就精简了许多,从最初的13行代码变化到6行代码,再到最后的3行代码。

【3】拓展

下面我们再了解下常用的 List 转 Map 的常见方式和一些注意事项:

【3.1】常见方式:

(3.1.1)List 转 Map,值为对象:

Map<Long, User> map = users.stream().collect(Collectors.toMap(User::getId, o -> o));

(3.1.2)List 转 Map,值为属性:

Map<Long, String> map = users.stream().collect(Collectors.toMap(User::getId, User::getName));

(3.1.3) List 转 Map,值为属性,且二次加工:

示例:姓名值后面统一加上一个 "_OK"字符

Map<Long, String> map = users.stream().collect(Collectors.toMap(User::getId, o -> o.getName() + "_OK"));

 

【3.2】注意事项:

(3.2.1)map 中的 key 值不能重复

首先我们先看下,正常数据的一段代码:

下面我们将103的Marry的ID改为104,这样我们的数据就存在了两个ID为104的记录,然后我们再运行一次程序,可以发现已经出现了异常:

其实,这个报错我们也能理解,毕竟所有Map的键是也不能重复的。

那么,我们通常会有哪些解决办法呢?

首先,我们可以以第一个键为准,后面的则自动忽略,

我们只需要在 Collectors.toMap() 方法里增加一个 Lamda表达式,具体写法如下:

可以看到,程序不再报异常,且第二个id为104的 Timi 已经被忽略了。

或者,我们采用覆盖原则,如果发现一个有重复的键,则自动覆盖之前值,具体方法如下:

可以发现,他与上个方式,唯一的区别就是选择的取值不同,没错,如果要想保留前面的数据就取参数1,要想保留后面的数据就取参数2。

你也许内心在想:如果我都想保留,可不可以呢?

当然可以!但这里Map值的类型是String类型,我们可以将所有ID相同的值连接,然后存放于Map中,写法如下:

可以看到,id = 104 的三个人都存于map中了。

(3.2.2)值不能为空

我们将id恢复正常,然后将最后一个的名称置空为null,运行程序:

可以发现,此时又出现了异常。

解决办法:我们可以将null值默认为空字符串,具体如下:

©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页