17

Is there a simple method to check if an element is contained in an iterable or iterator, analogous to the Collection.contains(Object o) method?

I.e. instead of having to write:

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

I would like to write:

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

I'm really surprised there is no such thing.

Roland
  • 7,525
  • 13
  • 61
  • 124

5 Answers5

22

In Java 8, you can turn the Iterable into a Stream and use anyMatch on it:

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

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

or using a method reference,

return StreamSupport.stream(data.spliterator(), false)
                    .anyMatch(myName::equals);
Stuart Marks
  • 127,867
  • 37
  • 205
  • 259
6

Guava has the functions Iterables.contains and Iterators.contains which do what you want. You can look at the source to see how to implement them yourself.

MikeFHay
  • 8,562
  • 4
  • 31
  • 52
3

An iterator is a sort of cursor which can be moved over the elements of any collection of elements. So its inner state is mainly the pointer to the current element. If you would try to find out whether it "contains" a certain element you would have to move the cursor and therefore modify the inner state. Modifying the state by simply asking a question is surely a bad thing to do.

That is even the problem with the mentioned Guava. It will modify the iterator object by simply calling the contains method.

An iterable on the other hand is simply an interface telling the compiler that there is something to iterate over. In most cases the iterable object will be the collection itself. If you would add methods like "contains" to the interface Iterable you would get a (simplified) version of the Collection interface - which already exists. So there is no need for that.

If you are stuck in your code at some place where you have a reference to an iterable but need functionality of a collection you should think about refactoring your code. Either you should use the interface collection consistently or ask yourself why you should better not call collection methods at this point. So your problem is most probably a result of a suboptimal code design.

On the other hand I would consider it to be a strange thing to use Iterable as type for parameters or variables anyway. Technically you can do this but I think it is meant to be used in loops only.

Wolf S
  • 236
  • 1
  • 3
  • I get an Iterable using [Guava Splitter](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Splitter.html#split(java.lang.CharSequence)), I can't use the newer `splitToList` because we are using an older version here at the company. – Roland Oct 27 '14 at 14:48
  • 1
    Well then bad code design is by google and they realized it themselves by now ;-) – Wolf S Oct 27 '14 at 14:58
  • I think the Collections class could add a contains method that accepts an Iterable. I'm talking about Collections, not Collecion. – Roland Oct 30 '14 at 09:20
  • **If you would add methods like "contains" to the interface Iterable you would get a (simplified) version of the Collection interface - which already exists. So there is no need for that.** There is a need. Consider that `Path` is `Iterable` but not a `Collection`, so it would make sense to be able to check if `Path` contains a certain element. – Roland Aug 23 '16 at 07:19
0

From the JavaDoc for Iterable:

Implementing this interface allows an object to be the target of the "foreach" statement

I'm sorry to say what you're trying to do is impossible.

.contains is a method of the interface Collection and not Iterable so maybe you can use that interface.

Jonathan
  • 20,053
  • 6
  • 63
  • 70
Guy Marom
  • 166
  • 1
  • 9
-1

An Iterator is like a pointer/reference to an element in a collection. It is not the collection itself. So, you can't use iterator.contains(). Also, an Iterable interface is used to iterate over a collection using a for-each loop. A collection and Iterator / Iterable are different.

TheLostMind
  • 35,966
  • 12
  • 68
  • 104