可迭代对象和迭代器的包含方法?

17

是否有一种简单的方法可以检查元素是否包含在可迭代对象或迭代器中,类似于Collection.contains(Object o)方法?

也就是说,不必编写以下代码:

Iterable<String> data = getData();
for (final String name : data) {
    if (name.equals(myName)) {
        return true;
    }
}

我想写:

Iterable<String> data = getData(); 
if (Collections.contains(data, myName)) {
    return true;
}

我真的很惊讶居然没有这样的东西。


1
如果您受限于JDK库,我不认为有直接的方法来实现这个。 - Dave Newton
5个回答

22

在Java 8中,您可以将Iterable转换为Stream并在其上使用anyMatch

String myName = ... ;
Iterable<String> data = getData();

return StreamSupport.stream(data.spliterator(), false)
                    .anyMatch(name -> myName.equals(name));

或者使用方法引用,

return StreamSupport.stream(data.spliterator(), false)
                    .anyMatch(myName::equals);

6

3
迭代器是一种可以在任何元素集合上移动的光标。因此,它的内部状态主要是指向当前元素的指针。如果您想查找它是否“包含”某个元素,则必须移动光标,因此修改内部状态。仅通过提问来修改状态肯定是不好的事情。
这甚至是Guava所提到的问题。它将通过简单调用contains方法来修改迭代器对象。
另一方面,可迭代只是一个接口,告诉编译器有东西可以迭代。在大多数情况下,可迭代对象将是集合本身。如果您将“包含”等方法添加到Iterable接口中,则会获得(简化的)Collection接口版本-已经存在,因此没有必要这样做。
如果您在代码的某个地方卡住了,其中有一个对可迭代对象的引用,但需要集合功能,则应考虑重构代码。您应该始终使用集合接口,或者问问自己为什么在此时最好不要调用集合方法。因此,您的问题很可能是次优代码设计的结果。
另一方面,我认为将Iterable用作参数或变量类型是一件奇怪的事情。从技术上讲,您可以这样做,但我认为它只应在循环中使用。

我使用 Guava Splitter 获取一个 Iterable,由于我们公司使用的是较旧版本,因此无法使用更新的 splitToList - Roland
1
那么,糟糕的代码设计是由谷歌自己意识到的,他们现在已经意识到了;-) - Wolf S
我认为Collections类可以添加一个接受Iterable的contains方法。我说的是Collections,而不是Collecion。 - Roland
如果您将像“contains”这样的方法添加到Iterable接口中,您将获得Collection接口的(简化)版本 - 该接口已经存在。因此没有必要这样做。但实际上是有必要的。考虑到Path是Iterable但不是Collection,因此检查Path是否包含某个元素是有意义的。 - Roland

0

来自Iterable的JavaDoc

实现此接口允许对象成为“foreach”语句的目标

很抱歉告诉你,你想做的事情是不可能的。

.contains是Collection接口而不是Iterable接口的方法,因此您可以尝试使用该接口。


-1

Iterator类似于指向集合中元素的指针/引用。它本身不是集合。因此,您不能使用iterator.contains()。同时,Iterable接口用于使用for-each循环迭代集合。集合、Iterator和Iterable都是不同的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接