【问题标题】:Get only element of a collection view with Guava, without exception when there are multiple elements使用 Guava 仅获取集合视图的元素,当有多个元素时无例外
【发布时间】:2013-02-07 10:25:27
【问题描述】:

我想要两个功能。第一个将给定一个集合,返回满足谓词的元素。谓词可能非常昂贵,并且结果不会被完全消耗,所以我认为最好的做法是返回一个视图。因此,一旦实现,我的方法就是封装了 Guava 的 Collections2.filter 的东西:

Collection<MyElement> getInterestingElements(Collection<MyElement> allElements) {
    return Collections2.filter(allElements, new Predicate<MyElement>() {
        @Override
        public boolean apply(MyElement element) {
            return element.isInteresting();  // call expensive function
        }
    });
}

(已更改类名以保护无辜者)

我的第二个函数将调用第一个函数并返回:

  • 如果集合包含零个或多个元素,则为 null。
  • 如果集合仅包含一个元素,则该集合的唯一元素。

也就是说,当且仅当此集合是单例时,此函数才会返回集合的内容。

一个简单的实现是:

MyElement getElementIfOnlyInterestingOne(Collection<MyElement> allElements) {
    Collection<MyElement> interestingElements = getInterestingElements(allElements);

    if (interestingElements.size() != 1){
        return null;
    }

    return Iterables.first(interestingElements, null);
}

但是对size() 的调用(我认为)将评估基础集合中所有元素的谓词,而当我只对第一个元素感兴趣时,这是不可接受的。

我可以使用 Iterables.getOnlyElement() ,但如果集合不是单例,这会抛出异常,这应该经常发生,我认为依赖异常来做这件事是一种不好的做法。

所以我必须手动迭代,将第一个元素存储在一个变量中,如果有第二个元素则返回 null。

我的问题是:这很好,但我不是在重新发明轮子吗? Guava 有这么多的魔力,这个问题必须通过 isSingletongetSingleElementOrNull 在某个地方解决:)

【问题讨论】:

    标签: java guava


    【解决方案1】:

    “番石榴方式”是使用FluentIterablefirstMatch 方法,该方法返回Optional 实例。在你的情况下:

    MyElement interestingOrNull = FluentIterable.from(allElements)
        .firstMatch(new Predicate<MyElement>() {
          @Override
          public boolean apply(MyElement element) {
            return element.isInteresting();
          }
        })
        .orNull();
    

    (更“番石榴方式”毕竟不会使用null...)

    【讨论】:

    • 好干净的方式。如前所述,可以改进,fromMatch 返回一个 Optional,您可以在对结果执行任何操作之前检查它是否存在。然后您可以在 or() 中返回 Optional.absent() 以确保没有空指针。
    • 当且仅当只有一个有趣的值时才满足返回值的要求。
    【解决方案2】:

    如果必须按照描述的方法实现该方法,其中包含除一个元素以外的任何元素的过滤集合必须返回 null,那么我能想到的最好的解决方案就是您已经建议的解决方案。

    Collection<MyElement> interestingElements = getInterestingElements(allElements);
    Iterator<MyElement> iterator = interestingElements.iterator();
    if (!iterator.hasNext()) {
        return null;
    }
    MyElement first = iterator.next();
    if (iterator.hasNext()) { // More than one element
        return null;
    } else {
        return first;
    }
    

    【讨论】:

      【解决方案3】:

      当然,上面的 FluentIterable 建议不处理问题的 size>2 => null 部分。就个人而言,我会使用 Iterables.getOnlyValue 方法。略显凌乱,但大大简化了代码,意图也很明确。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-03-04
        • 1970-01-01
        • 1970-01-01
        • 2016-02-26
        • 1970-01-01
        • 2022-10-15
        • 1970-01-01
        相关资源
        最近更新 更多