从流中获取唯一对象(如果存在)

时间:2019-05-22 14:55:51

标签: java java-stream

从具有单个相关属性的bean类MyBean开始:

@Data
class MyBean {
    private String myProperty;
}

现在,我有一组这些bean Set<MyBean> mySet,通常包含0、1或2个元素。

问题是:如果所有元素均相等,则如何从该集中检索myProperty,否则为null。最好是在单行中的努力为O(n)。

我发现了几个示例来确定所有属性是否相等的布尔值。但是我想知道相应的属性。

有比这更聪明的东西吗?

String uniqueProperty = mySet.stream().map(MyBean::getMyProperty).distinct().count() == 1 
    ? mySet.stream().map(MyBean::getMyProperty).findAny().orElse(null) 
    : null;

3 个答案:

答案 0 :(得分:0)

您的版本已经是O(n)

可以使用单线来完成此操作(尽管您的选择也取决于编写方式)。

String uniqueProperty = mySet.stream()
    .map(MyBean::getMyProperty)
    .map(Optional::ofNullable)
    .reduce((a, b) -> a.equals(b) ? a : Optional.empty())  // Note: equals compares 2 Optionals here
    .get()  // unwraps first Optional layer
    .orElse(null);  // unwraps second layer

唯一不起作用的情况是所有属性值均为null。例如,您无法将集合(null, null)(null, "A")区别开来,它们都返回null

答案 1 :(得分:0)

对于这种用例,仅一次迭代而不使用流看起来会更好:

Iterator<MyBean> iterator = mySet.iterator();
String uniqueProperty = iterator.next().getMyProperty();
while (iterator.hasNext()) {
    if (!iterator.next().getMyProperty().equals(uniqueProperty)) {
        uniqueProperty = null; // some default value possibly
        break;
    }
}

答案 2 :(得分:0)

您首先使用findAny(),然后再次使用mySet来检查allMatch(),以要求所有项目都与filter()中的第一个项目匹配:

String uniqueProperty = mySet.stream().findAny().map(MyBean::getMyProperty)
        .filter(s -> mySet.stream().map(MyBean::getMyProperty).allMatch(s::equals))
        .orElse(null);

这样做的好处是allMatch()仅在必要时评估所有元素(docs)。