Java 8 stream groupingBy String value

时间:2018-04-01 17:52:19

标签: java java-stream

我有一个包含以下格式的数据的JSON文件:

{
    "type":"type1",
    "value":"value1",
    "param": "param1"
}
{
    "type":"type2",
    "value":"value2",
    "param": "param2"
}

我也有这样一个对象:

public class TestObject {
    private final String value;
    private final String param;

    public TestObject(String value, String param) {
        this.value = value;
        this.param = param;
    }
}

我想要的是创建一个Map<String, List<TestObject>>,其中包含每种类型的TestObject列表。

这就是我编码的内容:

Map<String, List<TestObject>> result = jsonFileStream
                .map(this::buildTestObject)
                .collect(Collectors.groupingBy(line -> JsonPath.read(line, "$.type")));

方法buildTestObject是:

private TestObject buildTestObject(String line) {
    return new TestObject(
               JsonPath.read(line, "$.value"),
               JsonPath.read(line, "$.param"));
}

这不起作用,因为map()函数返回TestObject,因此collect函数不再适用于JSON String行。

在现实生活中,我无法添加&#34;类型&#34;变量到TestObject文件,因为它是来自外部库的文件。

如何按JSON文件中的类型对TestObject进行分组?

3 个答案:

答案 0 :(得分:4)

您可以将映射操作移动到groupingBy的下游收集器:

Map<String, List<TestObject>> result = jsonFileStream
    .collect(Collectors.groupingBy(line -> JsonPath.read(line, "$.type"),
        Collectors.mapping(this::buildTestObject, Collectors.toList())));

这将保留字符串,以便您可以将类型提取为分类器,并将映射应用于结果组的元素。

答案 1 :(得分:1)

您还可以使用toMap收集器来完成手头的任务。

Map<String, List<TestObject>> resultSet = jsonFileStream
           .collect(Collectors.toMap(line -> JsonPath.read(line, "$.type"),
                  line -> new ArrayList<>(Collections.singletonList(buildTestObject(line))),
                  (left, right) -> {
                      left.addAll(right);
                      return left;
                 }
           ));

答案 2 :(得分:0)

除了Stream解决方案之外,值得指出的是Java 8还显着改进了Map接口,制作了这种东西 使用for循环实现的痛苦比之前的情况要少得多。我不熟悉您正在使用的库,但是这样的内容可以使用(您始终可以将Stream转换为Iterable)。

Map<String, List<TestObject>> map = new HashMap<>();
for (String line : lines) {
    map.computeIfAbsent(JsonPath.read(line, "$.type"), k -> new ArrayList<>())
       .add(buildTestObject(line)); 
}