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

- 日理万妓 2022-12-08 04:24 252阅读 0赞

【前言】

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

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

  1. public class User {
  2. // 用户ID
  3. private long id;
  4. // 用户名称
  5. private String name;
  6. // 相关constrator,getter,setter,toString()方法已省略

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

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

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

我们也许会如下这么做:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70

运行程序得到结果为:

20200917164313406.png

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

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 1

【2】引入 Collectors.toMap()

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

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 2

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

20200917171032778.png

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

【3】拓展

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

【3.1】常见方式:

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

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

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

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

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

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

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

【3.2】注意事项:

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 3

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 4

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

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

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 5

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 6

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

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 7

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

(3.2.2)值不能为空

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 8

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

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3N1bm55enlx_size_16_color_FFFFFF_t_70 9

发表评论

表情:
评论列表 (有 0 条评论,252人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java8实现ListMap

    > 这些仅仅是在开发中遇到的一些转换,总结一下! > `List里面的对象元素,以某个属性来分组,例如,以id分组,将id相同的放在一起` > `List 以ID分组`

    相关 java ListMap

    在平时的编程过程中,list和map是集合中最常遇到的两种,熟练使用这两种集合是程序员必须具备的技能,list转map的应用常见也是很常遇到的,结合我最近的一个使用场景说一下: