JDK-8023225 : j.u.Collections.nCopies() instance is not conformant to Collection.removeIf() spec
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Not an Issue
  • Submitted: 2013-08-19
  • Updated: 2013-09-05
  • Resolved: 2013-09-05
Related Reports
Relates :  
Description
Specification for Collections.nCopies() says:

"Returns an immutable list consisting of n copies of the specified object."

However its iterator doesn't throw UOE, but throws ISE and calling of method removeIf(alwaysFalse) doesn't lead to the expected UnsupportedOperationException.

http://download.java.net/jdk8/docs/api/java/util/Collection.html#removeIf(java.util.function.Predicate)
"Throws:
UnsupportedOperationException - if the remove method is not supported by this collection's iterator()"


Please see the following code sample:

        final List<String> nCopies = Collections.nCopies(3, "a");

        try {
            nCopies.iterator().remove();
        } catch (UnsupportedOperationException uoe) {
            System.out.println("OK, remove method is not supported");
        } catch (Exception e) {
            System.out.println("e = " + e);
        }

        nCopies.removeIf( e -> false);


The output will be:

e = java.lang.IllegalStateException

The following JCK test will fail:
api/java_util/Collections/ncopies/RemoveIf.html#RemoveIf[elementRemovalNotSupported]






Comments
In this case it means adding an undesired default replacing implementation to throw the UOE. Unless previous() or next() has been successfully called, ISE is just as valid as UOE for this case. Consider changing the test to : nCopies.iterator().next().remove(); Which will generate a UOE.
05-09-2013

ArrayList is mutable so will never throw a UOE on remove. A List returned from Collections.unmodifableList will consistently throw UOE if remove is called on it's iterator. It seems reasonable for an "immutable" collection (unmodifiable view or actually immutable) to consistently throw UOE if the implementation is not expensive.
20-08-2013

I would expect the nCopies list to behave as closely as possible to a real list. The current ISE/UOE behaviour matches what happens for a more standard list such as ArrayList. I would hesitate to uniformly throw UOE.
19-08-2013

The nCopies list implementation extends from AbstractList where the implementation of the iterator will return an ISE if next is not yet called. If next is called, then remove, then a UOE is thrown. The docs on Iterator.remove states: * @throws IllegalStateException if the {@code next} method has not * yet been called, or the {@code remove} method has already * been called after the last call to the {@code next} * method It's a little vague but we might be OK. Even though remove is unsupported it can still be illegal to call remove when there is nothing that could be removed. However, in this case i think i would be inclined to consistently throw USO, and write a simple counting Iterator impl that is anyway more efficient (since there is no need for co-modification checks) at the expensive of slightly more code.
19-08-2013