AbstractMap.SimpleEntry 解决了我要一次性构造Map的需求

2 阅读2分钟
  1. 最简单的场景, 我有这么个对象集合, 为了代码简洁, 示例均不考虑key冲突场景.
@Data
public class TestModel {
    private Long id;
    private BigDecimal taxRate;
}

我要是想构造一个id为key, taxRate为value的Map, 就很简单, 像这样.

var testModel = new ArrayList<TestModel>();
var idValueMap = testModel.stream()
    .collect(Collectors.toMap(TestModel::getId, TestModel::getTaxRate));

  1. 突然数据结构变了, id变成了列表.
@Data
public class TestModel {
    private BigDecimal taxRate;
    private List<Long> ids;
}

我要是想构造的Map以ids中的每一个id为key, 怎么搞呢, 上代码.

public static void main(String[] args) {
    var testModels = List.of(new TestModel(BigDecimal.ONE, List.of(1L, 2L, 3L)),
                             new TestModel(BigDecimal.TEN, List.of(4L, 5L, 6L)));

    Map<Long, BigDecimal> idValueMap = testModels.stream()
        .flatMap(tm -> tm.getIds().stream()
            .map(id -> new AbstractMap.SimpleEntry<>(id, tm.getTaxRate()) {
            }))
        .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
    System.out.println(idValueMap);
}

输出结果如图:

image.png

  1. 突然数据结构又变了, 像这样
@Data
@AllArgsConstructor
public class TestModel {
    private BigDecimal taxRate;
    private List<Long> ids;
    private List<Long> orderIds;
}

我要构造一个Map嵌套的结构, 是这样Map<ids.id, Map<orderIds.id, value>> , 怎么搞呢, 上代码

public static void main(String[] args) {
    var testModels = List.of(new TestModel(BigDecimal.ONE, List.of(1L, 2L, 3L), List.of(7L, 8L, 9L)),
                             new TestModel(BigDecimal.TEN, List.of(4L, 5L, 6L), List.of(17L, 18L, 19L)));

    Map<Long, Map<Long, BigDecimal>> result = testModels.stream()
        .flatMap(tm -> tm.getIds().stream()
            .map(id -> new AbstractMap.SimpleEntry<>(id, tm.orderIds.stream()
                .map(oId -> new AbstractMap.SimpleEntry<>(oId, tm.getTaxRate()))
                .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue))
            ) {
            }))
        .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
    System.out.println(result);
}

输出结果如图:

image.png

  1. 假如数据结构又变了, 像这样
@Data
@AllArgsConstructor
public class TestModel {
    private List<Long> ids;
    private List<Long> orderIds;
    private List<TypeValue> typeValues;

    @Data
    static class TypeValue {
        private List<String> type;
        private String value;
    }
}

我还是想构造一个Map, 结构呢是这样Map<id, Map<orderId, Map<type, value>>>, 如果不允许定义额外的局部变量, 怎么写? 上代码

看答案之前, 先试试自己的java基本功扎实不扎实.

public static void main(String[] args) throws JsonProcessingException {
    var testModels = List.of(new TestModel(List.of(1L, 2L, 3L),
                                           List.of(7L, 8L, 9L),
                                           List.of(new TypeValue(List.of("a", "b", "c"), 1))),
                             new TestModel(List.of(4L, 5L, 6L),
                                           List.of(17L, 18L, 19L),
                                           List.of(new TypeValue(List.of("d", "e", "f"), 2))));

    Map<Long, Map<Long, Map<String, Integer>>> result = testModels.stream().flatMap(tm -> tm.getIds().stream().map(
        id -> new AbstractMap.SimpleEntry<>(id,
                                            tm.orderIds.stream().map(oId -> new AbstractMap.SimpleEntry<>(oId,
                                                                                                          tm.getTypeValues().stream().flatMap(
                                                                                                              tv -> tv.getType().stream().map(
                                                                                                                  t -> new AbstractMap.SimpleEntry<>(
                                                                                                                      t,
                                                                                                                      tv.getValue()))).collect(
                                                                                                              Collectors.toMap(
                                                                                                                  AbstractMap.SimpleEntry::getKey,
                                                                                                                  AbstractMap.SimpleEntry::getValue)))).collect(
                                                Collectors.toMap(AbstractMap.SimpleEntry::getKey,
                                                                 AbstractMap.SimpleEntry::getValue))) {
        })).collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
    ObjectMapper objectMapper = new ObjectMapper();
    System.out.println(objectMapper.writeValueAsString(result));
}

输出结果如下: 格式化后太长了, 我就不格式化了

{"1":{"7":{"a":1,"b":1,"c":1},"8":{"a":1,"b":1,"c":1},"9":{"a":1,"b":1,"c":1}},"2":{"7":{"a":1,"b":1,"c":1},"8":{"a":1,"b":1,"c":1},"9":{"a":1,"b":1,"c":1}},"3":{"7":{"a":1,"b":1,"c":1},"8":{"a":1,"b":1,"c":1},"9":{"a":1,"b":1,"c":1}},"4":{"17":{"d":2,"e":2,"f":2},"18":{"d":2,"e":2,"f":2},"19":{"d":2,"e":2,"f":2}},"5":{"17":{"d":2,"e":2,"f":2},"18":{"d":2,"e":2,"f":2},"19":{"d":2,"e":2,"f":2}},"6":{"17":{"d":2,"e":2,"f":2},"18":{"d":2,"e":2,"f":2},"19":{"d":2,"e":2,"f":2}}}

实际的业务场景是公司的财务系统中, 会从各种层级维度来设置税率相关的信息, 在查找税率时会产生类似示例代码的场景.