yangxu998 / guava-libraries

Automatically exported from code.google.com/p/guava-libraries
Apache License 2.0
0 stars 0 forks source link

Suggestion for Iterators and Iterables.findOnly #689

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
It would be helpful if there were a method in Iterators and Iterables that 
finds an element in a collection but checks that only one element was found.

Implementation would be something like this:

    public static <T> T findOnly(Iterator<T> iterator, Predicate<? super T> predicate) {
        UnmodifiableIterator<T> filteredIterator = Iterators.filter(iterator, predicate);
        T result = filteredIterator.next();

        if (filteredIterator.hasNext()) {
            throw new MultipleElementsFoundException(result, filteredIterator);
        }

        return result;
    }

    public static <T> T findOnly(Iterator<T> iterator, Predicate<? super T> predicate,
            @Nullable T defaultValue) {
        UnmodifiableIterator<T> filteredIterator = Iterators.filter(iterator, predicate);
        T result = filteredIterator.hasNext() ? filteredIterator.next() : defaultValue;

        if (filteredIterator.hasNext()) {
            throw new MultipleElementsFoundException(result, filteredIterator);
        }

        return result;
    }

Original issue reported on code.google.com by dancerj...@gmail.com on 15 Aug 2011 at 7:01

Attachments:

GoogleCodeExporter commented 9 years ago
This is an interesting suggestion, and I've definitely encountered this use 
case in the past. But I wonder whether such a method has a high enough 
"power-to-weight" ratio to be included in Guava.

Couldn't you do this by combining Iterables.filter() with 
Iterables.getOnlyElement()?

Iterables.getOnlyElement(Iterables.filter(iterable, predicate));
Iterators.getOnlyElement(Iterators.filter(iterator, predicate));
Iterables.getOnlyElement(Iterables.filter(iterable, predicate), defaultValue);
Iterators.getOnlyElement(Iterators.filter(iterator, predicate), defaultValue);

It seems to do exactly what you are looking for. Sure, it's more verbose, but I 
think it's well within Guava's design goal of having simple, composable methods.

Moreover, this approach lets you build your own variations as needed, e.g. 
replacing Iterables.getOnlyElement() with Iterables.getFirst(), or 
Iterables.filter(iterable, predicate) with Iterables.filter(iterable, type).

Original comment by nev...@gmail.com on 15 Aug 2011 at 9:43

GoogleCodeExporter commented 9 years ago
Although I agree with your assessment, I have one further suggestion regarding 
this method. Having an explicit exception for the multiple entries found where 
the matched elements are included in the exception improves the readability of 
code using this method. It also facilitates debugging by being able to output 
the matched elements in the stack trace.

However, I concede that this may still not pass the "power-to-weight" 
threshold. 

Gotta say, love the library.

Original comment by dancerj...@gmail.com on 16 Aug 2011 at 10:27