使用流将集合缩减为另一种类型的单个对象

时间:2018-04-19 13:01:08

标签: java java-8 java-stream

我找不到使用Java流将一种类型(例如MyData)的集合减少到另一种类型的对象(例如MyResult)的解决方案。

@Test
public void streams() {
    List<MyData> collection = Arrays.asList(
            new MyData("1", "cool"), 
            new MyData("2", "green"),
            new MyData("3", "night"));

    // How reduce the collection with streams?
    MyResult result = new MyResult();
    collection.stream().forEach((e) -> {
        if (e.key.equals("2")) {
            result.color = e.value;
        }
    });

    MyResult expectedResult = new MyResult();
    expectedResult.color = "green";
    assertThat(result).isEqualTo(expectedResult);
}

public static class MyData {
    public String key;
    public String value;

    public MyData(String key, String value) {
        this.key = key;
        this.value = value;
    }
}

public static class MyResult {
    public String color;
    public String material;

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        MyResult myResult = (MyResult) o;
        return Objects.equals(this.color, myResult.color) &&
                Objects.equals(this.material, myResult.material);
    }

    @Override
    public int hashCode() {
        return Objects.hash(this.color, this.material);
    }
}

是否有使用某种减少或折叠的解决方案?

5 个答案:

答案 0 :(得分:10)

你的意思是:

collection.stream()
        .filter(e -> e.key.equals("2"))
        .findFirst()
        .orElse(null);//Or any default value

你甚至可以抛出异常:

collection.stream()
        .filter(e -> e.key.equals("2"))
        .findFirst()
        .orElseThrow(() -> new IllegalArgumentException("No data found"));

答案 1 :(得分:1)

您是否尝试根据条件将某种类型的列表转换为另一种类型?

MyResult result = new MyResult();
        List<MyResult> resultList = collection.stream().filter(e -> e.key.equals("2")).map(e -> {
            MyResult resultTemp = new MyResult();
            result.color = e.value;
            return result;
        }).collect(Collectors.toList());

试试这个

答案 2 :(得分:0)

您可以先找到您正在寻找的元素

Optional<MyData> found = stream.filter(data -> data.key == 2).findFirst();

然后将其映射到您的结果

Optional<MyResult> result = found.map(data -> { 
        MyResult r = new MyResult(); 
        r.color = data.color; 
        return r; 
});

如果原始流不包含带有键2的项目,则匹配Optional,现在您的MyResult为空。

答案 3 :(得分:0)

您正在寻找的操作是Map。请阅读Stream文档以获取更多详细信息:https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

这是一个代码片段,用于将MyData对象列表映射到MyResult对象列表。

    List<MyResult> collect = collection.stream().map(myData -> {
        MyResult myResult = new MyResult();
        myResult.color = myData.value;
        return myResult;
    }).collect(Collectors.toList());

如果您只想找到一个值,只需在Map转换之前添加滤镜转换。

    List<MyResult> collect = collection.stream()
            .filter(myData -> "2".equals(myData.key))
            .map(myData -> {
                MyResult myResult = new MyResult();
                myResult.color = myData.value;
                return myResult;
            }).collect(Collectors.toList());

答案 4 :(得分:0)

我找到了使用Collector.of()的解决方案。

Collector<MyData, MyResult, MyResult> myCollector = Collector.of(
        () -> new MyResult(),
        (a, e) -> {
            if (e.key.equals("2")) {
                a.color = e.value;
            }
        },
        (a1, a2) -> null, // Not used, therefore not working scaffold
        a -> a
);
MyResult result = collection.stream().collect(myCollector);

毕竟它不是习惯性的。