使用Guava时,只获取集合视图的元素,当有多个元素时,无一例外

Cyr*_* Ka 3 java guava

我想要两个功能.给定Collection时,第一个将返回满足谓词的元素.谓词可能非常昂贵,结果不会完全消耗,所以我认为最好的做法是返回一个视图.因此,一旦实现,我的方法只是封装了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
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

(班级名称已被更改以保护无辜者)

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

  • 如果集合包含零个或多个元素,则返回null.
  • 如果集合只包含一个元素,则集合中唯一的元素.

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

一个天真的实现将是:

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

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

    return Iterables.first(interestingElements, null);
}
Run Code Online (Sandbox Code Playgroud)

但是对size()意志的调用(我认为)会评估底层集合的所有元素的谓词,当我只对第一个元素感兴趣时,这是不可接受的.

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

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

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

Xae*_*ess 10

"Guava方式"将是使用返回实例FluentIterablefirstMatch方法Optional.在你的情况下:

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

(甚至更多的"番石榴方式" null毕竟不会使用...)


Pau*_*ing 7

如果必须按照描述的方式实现方法,其中必须返回除了一个元素之外的任何其他元素的过滤集合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;
}
Run Code Online (Sandbox Code Playgroud)