45

Iterables present two methods for getLast

 public static <T> T getLast(Iterable<T> iterable);
 public static <T> T getLast(Iterable<T> iterable, @Nullable T defaultValue);

but only one for getFirst

 public static <T> T getFirst(Iterable<T> iterable, @Nullable T defaultValue);

Is there are any design/implementation reason for breaking symmetry?

sebkur
  • 658
  • 2
  • 9
  • 18
Stan Kurilin
  • 15,614
  • 21
  • 81
  • 132
  • possible duplicate of [In Google Guava (Java), why are Iterables.getFirst() and getLast() are inconsistent?](http://stackoverflow.com/questions/7832479/in-google-guava-java-why-are-iterables-getfirst-and-getlast-are-inconsist) – Dave L. Mar 06 '12 at 21:14
  • Maybe you can use [Iterables.getOnlyElement](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Iterables.html#getOnlyElement(java.lang.Iterable)) – Fabian Zeindl Sep 24 '14 at 15:07
  • 1
    @FabianZeindl - `getOnlyElement` throws `IllegalArgumentException` if there are more than one element. `getLast` should not do such thing. – Stan Kurilin Sep 24 '14 at 17:21
  • That's why I meant "maybe" -> in some situations. – Fabian Zeindl Sep 24 '14 at 21:01

2 Answers2

42

I think the point is that there is no reason for a getFirst(iterable) in that this could be done with iterable.iterator().next(). Guava makes an excellent attempt to keep the API small and so does not add things that could / should be done easily another way.

On the other hand, there is not already a mechanism to test if an iterable is empty and if so return a default value instead of the first value. Hence, getFirst(iterable, default).

Also, there is not a simple way to get the last element, hence getLast(iterable) and getLast(iterable, default)

Chris Povirk
  • 3,738
  • 3
  • 29
  • 47
John B
  • 32,493
  • 6
  • 77
  • 98
  • 2
    An alternative to `next()` would be `get(iterable, 0)`. – Daniel Fischer Dec 12 '11 at 11:58
  • true but I was staying with the `Iterable` API to show why Guava didn't add `getFirst(iterable)`. The addition of `get(iterable, index)` is not the reason `getFirst(iterable)` doesn't exist since `get(iterable, index, default)` has not prevented them from adding `getFirst(iterable, default)` – John B Dec 12 '11 at 12:01
  • Good point. Actually I don't think about guava as library with small API. Just because there are methods that just duplicate standard one, like `Doubles.compare`. And taking in mind @Daniel Fischer point, I believe there should be some other reasons provided. – Stan Kurilin Dec 12 '11 at 12:03
  • They actually do make a real effort to keep the API small. If you go on their issues site to request new methods they reject a lot of requests because they consider them to be bloat or not useful enough to warrant addition. If you compare it to Functional Java's API you will see what I mean. FJ has got tons of stuff but it is also a bit overwhelming. – John B Dec 12 '11 at 12:04
  • `iterable.next()` should be `iterable.iterator().next()`... but yes, this is the reason I believe. – ColinD Dec 12 '11 at 14:29
  • 3
    I've often been bitten by the absence of `Iterables.getFirst()`. I then double-check and use `Iterables.get(iterable, 0)`. I think `Iterables.getFirst()` would look cleaner, but oh well... – Etienne Neveu Dec 12 '11 at 15:52
  • 1
    We *do* make an effort to keep the API very small, and that was the motivation for not having Iterables.getFirst, to the best of my knowledge. I'm actually shocked that Doubles.compare is in there, I'm going to file an issue on that now... – Louis Wasserman Dec 12 '11 at 21:11
24

As an additions to @JohnB's answer I'd like to show Guava's devs opinion about getFirst(iterable). Kevin Bourrillion (head Guava's dev) writes there:

iterable.iterator().next() is perfectly clear and readable and unambiguous. I know exactly what it does, whereas with Iterators.getFirst(), I have to run off and look up how that library designer decided to do it.

Also, your notion of consistency is deeply misguided. We use consistency in how we present important functionality, but we never use it to justify adding worthless functionality, and you shouldn't in your own libraries either!

So, you have a choice:

  • using iterable.iterator().next(),
  • using Iterables.getFirst(Iterable<T> iterable, T default),
  • using Iterables.get(Iterable<T>, 0),
  • writing your own method (probably containing iterable.iterator().next() and some docs) and use it as i.e. Iterables2.getFirst(iterable),
  • waiting for Kevin to change his mind ;)

PS: I had similar doubt some time ago and found exact duplicate of this question at that time.

Community
  • 1
  • 1
Grzegorz Rożniecki
  • 27,415
  • 11
  • 90
  • 112