Collection Interface in Java: Methods and Contract - Quiz

Total: 6 questions

1. 

What is the Collection interface in Java, and which methods does it declare?

java.util.Collection<E> is the root interface of the list, set and queue branch of the Java Collections Framework. It extends Iterable<E> and declares the operations shared by List, Set and Queue. Map does not extend Collection.

Its methods fall into three groups:

  • modifying the collection: add, remove, addAll, removeAll, retainAll, removeIf, clear;
  • querying it: contains, containsAll, size, isEmpty;
  • iterating and converting it: iterator, toArray, stream, parallelStream, spliterator (plus forEach from Iterable).

equals() and hashCode() are also redeclared in Collection. There are no index-based methods such as get(int): sets and queues have no element positions, so indexes exist only in List.

2. 

What do the add(), addAll(), remove(), removeAll(), retainAll() and removeIf() methods of the Collection interface return?

All of them return a boolean: true if the collection changed and false if it stayed the same. If an implementation refuses an operation for any other reason, it throws an exception instead of returning false.

  • add(e) — false, for example, for a Set that already holds the element.
  • addAll(c) — true if at least one element was added: for a HashSet that already had some of the elements, the result is still true.
  • remove(o) — removes only the first occurrence equal to o by equals().
  • removeAll(c) — removes every element that is also in c, including duplicates; elements of c that are missing do not prevent a true result.
  • retainAll(c) — keeps only the elements that are in c; true if anything was removed.
  • removeIf(filter) — removes the elements that match the condition; true if at least one was removed.
3. 

What are the optional operations of Collection, and why does List.of("a", "b").remove("z") throw an exception while Arrays.asList("a", "b").remove("z") returns false?

The methods that modify a collection (add, addAll, remove, removeAll, retainAll, removeIf, clear) are marked as optional operations in the Javadoc. An implementation may choose not to support them and throw UnsupportedOperationException. That is how List.of(), Collections.unmodifiableCollection() and, for size-changing operations, Arrays.asList() work.

If a call would not change the collection, an optional operation may throw the exception, but it does not have to. Collections created by List.of() refuse immediately, without looking at the argument. The Arrays.asList() list searches for the element first and throws only when it really has to remove something: remove("z") returns false, while remove("a") throws UnsupportedOperationException.

In practice, a declaration like Collection<String> c does not tell you whether the object supports add(). If a method receives a collection from outside and needs to modify it, it is safer to work on a copy: new ArrayList<>(c).

4. 

What are the ways to get an array from a collection with toArray(), and does it copy the elements?

There are three overloads:

  • Object[] toArray() — returns an Object[]; it cannot be cast to String[] (ClassCastException) even if every element is a string;
  • <T> T[] toArray(T[] a) — an array of the requested type, usually toArray(new String[0]);
  • toArray(IntFunction<T[]> generator) (Java 11) — an array created from a constructor reference: toArray(String[]::new).

If the element type does not fit the array type, the last two overloads throw ArrayStoreException.

The array is always new and independent of the collection: assigning array[0] = ... does not change the collection. But the objects themselves are not copied — the array holds references to the same objects. If a list holds new StringBuilder("a"), then after ((StringBuilder) list.toArray()[0]).append("!") the list prints as [a!].

5. 

When are two collections equal by equals() in Java?

Collection itself does not define equality — its subinterfaces do:

  • two Lists are equal if they contain equal elements in the same order, regardless of the class: an ArrayList with [1, 2, 3] equals the same LinkedList;
  • two Sets are equal if they contain the same elements: a HashSet equals a TreeSet with the same elements;
  • a list is never equal to a set.

ArrayDeque, PriorityQueue and the map.values() collection are neither a List nor a Set and do not override equals(), so they are compared by reference: two deques with the same elements are not equal.

The hash code depends on the subinterface too: for a List it takes element order into account, for a Set it is the sum of the elements’ hash codes. The elements themselves are found by contains(), remove() and removeAll() with equals(), so your own classes need to override it.

6. 

How did the Collection interface change across Java versions, and why does it have default methods?

  • Java 1.2 — the interface appeared together with the Collections Framework: add, remove, contains, size, iterator, toArray and others.
  • Java 5 — it became generic (Collection<E>) and got the parent Iterable, which enables the for-each loop.
  • Java 8 — default methods removeIf(), stream(), parallelStream(), spliterator(); forEach() in Iterable.
  • Java 11 — default method toArray(IntFunction<T[]>).
  • Java 21 — the SequencedCollection subinterface.

Default methods have a body right in the interface. That is why new methods could be added to Collection without breaking existing classes that implement it: they did not have to add any code.

Page 1 of 1