18

I love Google Guava and use it a lot, but there is one method I always find me writing..

 public static <T> T tryFind(Iterable<T> iterable, Predicate<T> predicate){
     for(T t : iterable){
         if(predicate.apply(t)){
              return t;
         }
     }
     return null;
  }

To me this seems to be a very useful addition to Iterables (also to Iterators for that matter), so I'm wondering why it's missing. Also, while I can see the point of having a method that throws NoSuchElementException, perhaps to distinguish between finding a null and not finding the element, that situation only comes up if the predicate you are using is

public boolean apply(T t){
     return t==null;
}

which doesn't seem to be a common case.

So why did guava designers chose to have this behavior, instead of just returning null if it can't find it?

Here is the javadoc for [Iterables.find()][1]

[1]: http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Iterables.html#find(java.lang.Iterable, com.google.common.base.Predicate)

Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
  • Maybe it would have been better to throw a checked exception to prevent clients from forgetting it... – thSoft Jul 25 '11 at 13:24
  • Possible duplicate of [Iterables.find and Iterators.find - instead of throwing exception, get null](https://stackoverflow.com/questions/2543052/iterables-find-and-iterators-find-instead-of-throwing-exception-get-null) – Stewart Aug 07 '17 at 13:05

5 Answers5

32

We're adding another overload of find() which accepts a default value.

Kevin Bourrillion
  • 40,336
  • 12
  • 74
  • 87
  • 6
    `Iterables.find(iterable, predicate, defaultValue)` :) – Miguel Ping Jan 27 '12 at 15:56
  • 1
    What about a Optional tryFind(Iterable iterable, int position) ? Sometimes I don't have a default value available and would like to communicate that the caller of my api need to handle it. – jontejj Apr 22 '14 at 14:46
  • @jontejj we've made the methods work that way in `FluentIterable` but aren't bothering changing everything in `Iterables`, which is usually less convenient anyway. – Kevin Bourrillion Nov 02 '14 at 16:52
  • I am having difficulty understanding this answer. How could this be the answer? This should be a comment. I am having similar problem as well. – Neon Warge Aug 17 '16 at 05:32
13

Likely because null is a valid return value. Generally speaking, unless there is a good reason to not support null then it should be supported. If it is supported then you have to handle the case where it exists.

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
  • 1
    The need for a find() operation which returns null is highly questionable. Surely if you know that if there is a null in the collection at all, you will get null back, so you might as well just use contains, or some other simpler existing method. – Hakanai Sep 22 '11 at 06:22
5

Instead of tryFind() you can use filter and check if it returns an empty collection.

I found that always working with collections is cleaner than directly asking objects.

Peter Tillemans
  • 34,983
  • 11
  • 83
  • 114
  • 1
    In many cases the check is then no longer needed and you can immediately iterate over the results. Nothing will happen when there are no results, which is in my experience often is the desired behavour. – Peter Tillemans Jun 23 '10 at 07:36
  • Working with loops is cleaner. – Alex78191 Sep 26 '18 at 11:40
3

In my opinion, the NoSuchElementException is better than a late and very difficult to debug NPE... In most cases, when you are searching an object in a "collection", you know that you would probably find it. If the object you're looking for is not in the "collection", you're facing an exceptional case... According to me, the NoSuchElementException feedback is more explicit than the meaningless "null".

The default value which will be introduced in a future guava release would be an efficient shortcut to treat the exceptionnal case.

sly7_7
  • 11,961
  • 3
  • 40
  • 54
0

Find would make sense if it could not to find rather finding default value.

Optional<T> Iterables.find(Iterable<T>, Predicate<? super T>)