Java 转换List至Map

Java 转换List至Map

转换List至Map是很常见的任务。文本我们提供几种方式实现。假设List中的每个元素有一个唯一标识作为Map中的key。

示例数据结构

首先,我们定义模型数据:

@Data
public class Animal {
    private int id;
    private String name;
}

id字段值是唯一的,因此可以作为key。首先使用传统方法进行转换.

## java 8 之前方式

很显然,我们可以使用核心java API实现:

public Map<Integer, Animal> convertListBeforeJava8(List<Animal> list) {
    Map<Integer, Animal> map = new HashMap<>();
    for (Animal animal : list) {
        map.put(animal.getId(), animal);
    }
    return map;
}

测试代码:

@Test
public void whenConvertBeforeJava8_thenReturnMapWithTheSameElements() {
    Map<Integer, Animal> map = convertListService.convertListBeforeJava8(list);
     
    assertThat(map.values(), containsInAnyOrder(list.toArray()));
}

使用java 8 方式

Java 8 可以通过stream 和 Collectors实现:

public Map<Integer, Animal> convertListAfterJava8(List<Animal> list) {
    Map<Integer, Animal> map = list.stream()
      .collect(Collectors.toMap(Animal::getId, animal -> animal));
    return map;
}

再次进行测试:

@Test
public void whenConvertAfterJava8_thenReturnMapWithTheSameElements() {
    Map<Integer, Animal> map = convertListService.convertListAfterJava8(list);
     
    assertThat(
      map.values(), 
      containsInAnyOrder(list.toArray()));
}

使用Guava 库

除了java 提供的API,我们也可以使用第三方库实现转换,Guava 提供了Maps.uniqueIndex() 方法可以实现:

public Map<Integer, Animal> convertListWithGuava(List<Animal> list) {
    Map<Integer, Animal> map = Maps
      .uniqueIndex(list, Animal::getId);
    return map;
}

对应测试代码:

@Test
public void whenConvertWithGuava_thenReturnMapWithTheSameElements() {
    Map<Integer, Animal> map = convertListService
      .convertListWithGuava(list);
     
    assertThat(
      map.values(), 
      containsInAnyOrder(list.toArray()));
}

使用Apache Commons库

Apache Commons库提供了MapUtils.populateMap():

public Map<Integer, Animal> convertListWithApacheCommons2(List<Animal> list) {
    Map<Integer, Animal> map = new HashMap<>();
    MapUtils.populateMap(map, list, Animal::getId);
    return map;
}

测试代码:

@Test
public void whenConvertWithApacheCommons2_thenReturnMapWithTheSameElements() {
    Map<Integer, Animal> map = convertListService
      .convertListWithApacheCommons2(list);
     
    assertThat(
      map.values(), 
      containsInAnyOrder(list.toArray()));
}

键冲突

前面我们假设键对应值是唯一的,如果不唯一会出现什么情况。

首先,我们准备测试数据,id值有重复:

@Before
public void init() {
 
    this.duplicatedIdList = new ArrayList<>();
 
    Animal cat = new Animal(1, "Cat");
    duplicatedIdList.add(cat);
    Animal dog = new Animal(2, "Dog");
    duplicatedIdList.add(dog);
    Animal pig = new Animal(3, "Pig");
    duplicatedIdList.add(pig);
    Animal cow = new Animal(4, "Cow");
    duplicatedIdList.add(cow);
    Animal goat= new Animal(4, "Goat");
    duplicatedIdList.add(goat);
}

cow 和 goat的id都是4。

值重复情况测试对比

java Map的put方法实现为:键相同时后面的值会覆盖前面的值。因此,使用java 8 之前实现和Apache Commons MapUtils.populateMap() 方式结果一致:

@Test
public void whenConvertBeforeJava8_thenReturnMapWithRewrittenElement() {
 
    Map<Integer, Animal> map = convertListService
      .convertListBeforeJava8(duplicatedIdList);
 
    assertThat(map.values(), hasSize(4));
    assertThat(map.values(), hasItem(duplicatedIdList.get(4)));
}
 
@Test
public void whenConvertWithApacheCommons_thenReturnMapWithRewrittenElement() {
 
    Map<Integer, Animal> map = convertListService
      .convertListWithApacheCommons(duplicatedIdList);
 
    assertThat(map.values(), hasSize(4));
    assertThat(map.values(), hasItem(duplicatedIdList.get(4)));
}

我们看到,goat覆盖了cow的id。

相反,Collectors.toMap() 和 MapUtils.populateMap() 方法分别抛IllegalStateException和IllegalArgumentException异常:

@Test(expected = IllegalStateException.class)
public void givenADupIdList_whenConvertAfterJava8_thenException() {
 
    convertListService.convertListAfterJava8(duplicatedIdList);
}
 
@Test(expected = IllegalArgumentException.class)
public void givenADupIdList_whenConvertWithGuava_thenException() {
 
    convertListService.convertListWithGuava(duplicatedIdList);
}

解决办法

Collectors.toMap提供了重载方法,第三个参数提供meargeFunction,我们可以这样实现:

Map<Integer, Animal> map = list.stream()
    .collect(Collectors.toMap(Animal::getId, animal -> animal),(oldValue, newValue) -> newvalue);
return map;

当然你也可以写(oldValue, newValue) -> oldValue,保留原来的值,取决你的需要。

## 总结

本文我们探讨了几种方式实现list转换为map,同时说明了key值重复情况及解决办法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值