ArrayList.removeAll()/retainAll()

Benedict Elliott Smith belliottsmith at datastax.com
Tue Feb 4 17:47:27 UTC 2014


Hi Mike,

Thanks very much for the careful explanation, it's appreciated. It does
look trivial to fix, so I'll see about raising a ticket over there.


On 4 February 2014 17:35, Mike Duigou <mike.duigou at oracle.com> wrote:

> The condition that is causing the problem is not a collection containing
> null, which is allowed, but that the provided collection "c" is itself null.
>
> The problem was is a consequence of the following implementation:
>
> Iterator<E> iterator = iterator();
>
> while(iterator.hasNext()) {
>  if(c.contains(iterator.next()) {
>     iterator.remove();
>  }
> }
>
> This implementation had an inconsistent behaviour. If a collection
> contains elements then the first iteration of the while loops will cause a
> NullPointerException if "c" is null. If, however, the collection is empty
> then c is never referenced and no NPE is thrown. The change in java 8 which
> adds an explicit Objects.requireNonNull(c) ensures the behaviour is
> consistent whether the collection is empty or not. Passing null as the
> parameter for removeAll and retainAll has never been valid. What's changed
> is that it's now consistently checked.
>
> It's unfortunate that this particular fix tickled a bug in Antlr 3. It
> appears that it's simply a bug that Antlr doesn't check the result of it's
> method which returns null. (
> https://github.com/antlr/antlr3/blob/master/tool/src/main/java/org/antlr/tool/CompositeGrammar.java#L226)
> The fix would seem to be relatively straightforward to either have
> getDirectDelegates() return Collections.<Grammar>emptyList() or add a check
> for null. My personal preference would be for the former as it allows for
> uniform handling of the result wherever the method is called without having
> to remember that the result might be null.
>
> Mike
>
> On Feb 4 2014, at 09:00 , Benedict Elliott Smith <
> belliottsmith at datastax.com> wrote:
>
> > Hi,
> >
> > I notice this (or a related issue) has been mentioned
> > before<
> http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-June/017663.html
> >on
> > this list, but I'm not convinced the correct resolution was reached.
> > We
> > are seeing this problem thrown by antlr, but rather than a bug in antlr,
> as
> > surmised on the previous exchange, it looks to me that ArrayList is
> > imposing a new constraint that is neither declared by itself nor
> > Collection, and is unnecessary. ArrayList happily supports null elements,
> > so requiring that the provided collection has no null elements is surely
> a
> > bug?
> >
> > I've pasted the two declarations below for ease of reference. Neither
> > javadocs describe the constraint that is imposed.
> >
> > ArrayList:
> >    /**
> >     * Removes from this list all of its elements that are contained in
> the
> >     * specified collection.
> >     *
> >     * @param c collection containing elements to be removed from this
> list
> >     * @return {@code true} if this list changed as a result of the call
> >     * @throws ClassCastException if the class of an element of this list
> >     *         is incompatible with the specified collection
> >     * (<a href="Collection.html#optional-restrictions">optional</a>)
> >     * @throws NullPointerException if this list contains a null element
> > and the
> >     *         specified collection does not permit null elements
> >     * (<a href="Collection.html#optional-restrictions">optional</a>),
> >     *         or if the specified collection is null
> >     * @see Collection#contains(Object)
> >     */
> >    public boolean removeAll(Collection<?> c) {
> >        Objects.requireNonNull(c);
> >        return batchRemove(c, false);
> >    }
> >
> > Collection:
> >    /**
> >     * Removes all of this collection's elements that are also contained
> in
> > the
> >     * specified collection (optional operation).  After this call
> returns,
> >     * this collection will contain no elements in common with the
> specified
> >     * collection.
> >     *
> >     * @param c collection containing elements to be removed from this
> > collection
> >     * @return <tt>true</tt> if this collection changed as a result of the
> >     *         call
> >     * @throws UnsupportedOperationException if the <tt>removeAll</tt>
> > method
> >     *         is not supported by this collection
> >     * @throws ClassCastException if the types of one or more elements
> >     *         in this collection are incompatible with the specified
> >     *         collection
> >     *         (<a href="#optional-restrictions">optional</a>)
> >     * @throws NullPointerException if this collection contains one or
> more
> >     *         null elements and the specified collection does not support
> >     *         null elements
> >     *         (<a href="#optional-restrictions">optional</a>),
> >     *         or if the specified collection is null
> >     * @see #remove(Object)
> >     * @see #contains(Object)
> >     */
> >    boolean removeAll(Collection<?> c);
>
>



More information about the core-libs-dev mailing list