Java-8:流还是更简单的解决方案?

时间:2018-03-28 10:29:57

标签: java java-8 java-stream

我有两个模型List<ModelA>,我想将其转换为List<ModelB>。 这是我的模特:

class ModelA {

    private Long id;
    private String name;
    private Integer value;

    public ModelA(Long id, String name, Integer value) {
        this.id = id;
        this.name = name;
        this.value = value;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Integer getValue() {
        return value;
    }
}

class ModelB {
    private Long id;
    private Map<String, Integer> valuesByName;

    public ModelB(Long id, Map<String, Integer> valuesByName) {
        this.id = id;
        this.valuesByName = valuesByName;
    }

    public Long getId() {
        return id;
    }

    public Map<String, Integer> getValuesByName() {
        return valuesByName;
    }
}

实际解决方案:

public static List<ModelB> convert(List<ModelA> models) {
        List<ModelB> toReturn = new ArrayList<>();
        Map<Long, Map<String, Integer>> helper = new HashMap<>();
        models.forEach(modelA -> {
            helper.computeIfAbsent(modelA.getId(), value -> new HashMap<>())
                    .computeIfAbsent(modelA.getName(), value -> modelA.getValue());
        });
        helper.forEach((id, valuesByName) -> toReturn.add(new ModelB(id,valuesByName)));
        return toReturn;
    }

但我认为有一个更简单的解决方案,您是否知道如何在单个流中执行此操作,或以某种方式简化它?

编辑:我想澄清一下,我不能使用java9,我需要按照Id-s然后按名称对它们进行分组。如果在ModelB中我有4个具有相同id的元素,我不想要ModelA的新实例。

2 个答案:

答案 0 :(得分:7)

我已合并这两项操作,但仍构建中间地图,因为您需要分组给定 ID 的所有名称,值

models.stream()
        .collect(Collectors.groupingBy(model -> model.getId(), //ModelA::getId - Using method reference
                Collectors.toMap(model -> model.getName(), model -> model.getValue(), (map1, map2) -> map1)))
        .entrySet()
        .stream()
        .map(entry -> new ModelB(entry.getKey(), entry.getValue()))
        .collect(Collectors.toList());

修改

我在初步回答中错过了(map1, map2) -> map1。需要避免覆盖已存在的value idname(相当于代码中的第二个computeIfAbsent) 您需要选择其中一个(或修改它们),因为默认情况下它会在找到重复键时抛出IllegalStateException

答案 1 :(得分:-1)

使用Stream中的map函数

可轻松实现此目的
public static List<MobelB> convert(List<ModelA> models) {
  Map<Long, Map<String, Integer>> modelAMap = models.stream()
    .collect(Collectors.toMap(ModelA::getId, modelA -> computeMap(modelA)));

  return models.stream()
    .map(modelA -> new ModelB(modelA.getId(), modelAMap.get(modelA.getId())))
    .collect(Collectors.toList());
}

private static Map<String, Integer> computeMap(ModelA model) {
  Map<String, Integer> map = new HashMap<>();
  map.put(model.getId(), model.getName());
  return map;
}