getFirst and getLast on Iterable

Brian Goetz brian.goetz at oracle.com
Thu Apr 17 16:47:41 UTC 2014


In the course of JSR-335, we considered a number of possible methods on 
Iterable.  There are literally hundreds of methods that might "sensibly" 
appear on Iterable; see RichIterable from GS-Collections or IEnumerable 
from .NET for some examples.  After considering the landscape, we 
decided, basically, to not do any of them.

The reason is that Iterable is *so general* and *so ubiquitous* that 
adding new methods at this stage would carry an unreasonable risk of 
collision.  When viewed through the lens of "what is an Iterable", the 
meaning of a "getFirst()" is obvious enough.  (getLast(), not so much; 
this assumes there is a last, which is a bad assumption, given that 
there's no size() or isKnownFinite() method.)

The problem is, in the context of some Foo that implements 
Iterable<Bar>, methods like getFirst() or sorted() or filter() or ... 
might not obviously mean in the context of Foo what they obviously mean 
in the context of Iterable.  Iterable is too general.  And there are 
zillions of outstanding Iterable classes now, so the risk is high.

So given the choice between adding a zillion new methods, and adding 
zero (which is basically the choice, drawing the line is very hard and 
will always be under pressure to move "just one more method to the 
left"), we chose zero.

On 4/17/2014 7:52 AM, Otávio Gonçalves de Santana wrote:
> I would to add for news methods on Iterable, I believe it will helpful for
> many Java Developers.
>
>
> diff -r 3dd165facde7 test/java/util/Iterator/IteratorDefaults.java
>
> --- a/test/java/util/Iterator/IteratorDefaults.java Wed Apr 09 12:26:00
> 2014 -0700
>
> +++ b/test/java/util/Iterator/IteratorDefaults.java Wed Apr 16 23:25:56
> 2014 -0300
>
> @@ -399,6 +399,48 @@
>
>           }
>
>       }
>
>
>
> +     public void testgetFirst() {
>
> +
>
> +        List<Integer> source = Arrays.asList(1, 2, 3, 4);
>
> +        int first = source.getFirst();
>
> +        assertEquals(first, 1);
>
> +
>
> +        List<String> emptySource = Collections.<String>emptyList();
>
> +        assertNull(emptySource.getFirst());
>
> +    }
>
> +
>
> +    public void testgetFirstWithDefaultElement() {
>
> +
>
> +        List<Integer> source = Arrays.asList(1, 2, 3, 4);
>
> +        Integer defaultElement = 5;
>
> +        assertEquals(source.getFirst(defaultElement), Integer.valueOf(1));
>
> +
>
> +        List<Integer> emptySource = Collections.<Integer>emptyList();
>
> +        assertEquals(emptySource.getFirst(defaultElement), defaultElement);
>
> +
>
> +    }
>
> +
>
> +    public void testgetLast() {
>
> +
>
> +        List<Integer> source = Arrays.asList(1, 2, 3, 4);
>
> +        int last = source.getLast();
>
> +        assertEquals(last, 4);
>
> +
>
> +        List<String> emptySource = Collections.<String>emptyList();
>
> +        assertNull(emptySource.getLast());
>
> +    }
>
> +
>
> +    public void testgetLastWithDefaultElement() {
>
> +
>
> +        List<Integer> source = Arrays.asList(1, 2, 3, 4);
>
> +        Integer defaultElement = 5;
>
> +        assertEquals(source.getLast(defaultElement), Integer.valueOf(4));
>
> +
>
> +        List<Integer> emptySource = Collections.<Integer>emptyList();
>
> +        assertEquals(emptySource.getLast(defaultElement), defaultElement);
>
> +
>
> +    }
>
> +
>
>       static class IteratorWithRemove implements Iterator {
>
>
>
>           public boolean removed;
>
>
>
>
> diff -r 3dd165facde7 src/share/classes/java/lang/Iterable.java
>
> --- a/src/share/classes/java/lang/Iterable.java Wed Apr 09 12:26:00 2014
> -0700
>
> +++ b/src/share/classes/java/lang/Iterable.java Wed Apr 16 23:16:21 2014
> -0300
>
> @@ -100,4 +100,55 @@
>
>       default Spliterator<T> spliterator() {
>
>           return Spliterators.spliteratorUnknownSize(iterator(), 0);
>
>       }
>
> +
>
> +
>
> +   /**
>
> +     * returns the first element, if empty will return {@code null}
>
> +     * @return the first element or {@code null}
>
> +     * @since 1.8
>
> +     */
>
> +    default T getFirst() {
>
> +        return getFirst(null);
>
> +    }
>
> +
>
> +    /**
>
> +     * returns the first element, if empty will return the default
>
> +     * @param defaultValue - the default value to return if the iterable
> is empty
>
> +     * @return the first element or default element
>
> +     * @since 1.8
>
> +     */
>
> +    default T getFirst(T defaultValue) {
>
> +        for (T element : this) {
>
> +            return element;
>
> +        }
>
> +        return defaultValue;
>
> +    }
>
> +
>
> +  /**
>
> +     * returns the last element, if empty will return {@code null}
>
> +     * @return the first element or {@code null}
>
> +     * @since 1.8
>
> +     */
>
> +    default T getLast() {
>
> +
>
> +        return getLast(null);
>
> +    }
>
> +
>
> +    /**
>
> +     * returns the last element, if empty will return the default
>
> +     * @param defaultValue - the default value to return if the iterable
> is empty
>
> +     * @return the last element or default element
>
> +     * @since 1.8
>
> +     */
>
> +    default T getLast(T defaultValue) {
>
> +
>
> +        T last = null;
>
> +        for (T element : this) {
>
> +            last = element;
>
> +        }
>
> +        if (Objects.isNull(last)) {
>
> +            return defaultValue;
>
> +        }
>
> +        return last;
>
> +    }
>
>   }
>



More information about the core-libs-dev mailing list