Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The correct way to return the only element from a set

I have the following kind of situation:

Set<Element> set = getSetFromSomewhere(); if (set.size() == 1) {     // return the only element } else {     throw new Exception("Something is not right.."); } 

Assuming I cannot change the return type of getSetFromSomewhere(), is there a better or more correct way to return the only element in the set than

  • Iterating over the set and returning immediately
  • Creating a list from the set and calling .get(0)
like image 416
Janne Avatar asked Mar 08 '11 06:03

Janne


People also ask

What is the difference between a set and a list?

List is a type of ordered collection that maintains the elements in insertion order while Set is a type of unordered collection so elements are not maintained any order. List allows duplicates while Set doesn't allow duplicate elements .


1 Answers

You can use an Iterator to both obtain the only element as well as verify that the collection only contains one element (thereby avoiding the size() call and the unnecessary list creation):

Iterator<Element> iterator = set.iterator();  if (!iterator.hasNext()) {     throw new RuntimeException("Collection is empty"); }  Element element = iterator.next();  if (iterator.hasNext()) {     throw new RuntimeException("Collection contains more than one item"); }  return element; 

You would typically wrap this up in its own method:

public static <E> E getOnlyElement(Iterable<E> iterable) {     Iterator<E> iterator = iterable.iterator();      // The code I mentioned above... } 

Note that this implementation is already part of Google's Guava libraries (which I highly recommend, even if you don't use it for this particular code). More specifically, the method belongs to the Iterables class:

Element element = Iterables.getOnlyElement(set); 

If you're curious about how it is implemented, you can look at the Iterators class source code (the methods in Iterables often call methods in Iterators):

  /**    * Returns the single element contained in {@code iterator}.    *    * @throws NoSuchElementException if the iterator is empty    * @throws IllegalArgumentException if the iterator contains multiple    *     elements.  The state of the iterator is unspecified.    */   public static <T> T getOnlyElement(Iterator<T> iterator) {     T first = iterator.next();     if (!iterator.hasNext()) {       return first;     }      StringBuilder sb = new StringBuilder();     sb.append("expected one element but was: <" + first);     for (int i = 0; i < 4 && iterator.hasNext(); i++) {       sb.append(", " + iterator.next());     }     if (iterator.hasNext()) {       sb.append(", ...");     }     sb.append('>');      throw new IllegalArgumentException(sb.toString());   } 
like image 191
Adam Paynter Avatar answered Sep 28 '22 01:09

Adam Paynter