Java Collection Interface
Table of Contents + −
In the last lesson you learned about the Java Collections Framework. Now let’s zoom in on the piece that ties most of them together: the Collection interface. Understand this one interface and you understand the shared language that List, Set, and Queue all speak.
🤔 Why one shared interface matters
Say you write a method that counts items in a group. Without a shared interface, the pain piles up:
- You write one version for a List, copy it for a Set, copy it again for a Queue.
- Three near-identical methods, three places for a bug to hide.
- A method that only accepts
ArrayListcan never take aHashSet, even though counting fits both.
The Collection interface fixes this. It is the common contract that List, Set, and Queue all sign. So add, remove, size, and contains mean the same thing whatever you hold. Write your method against Collection once, and it works for every collection.
🧩 What is the Collection interface?
The Collection interface, written java.util.Collection, is the root interface for groups of single items:
- List, Set, and Queue all extend it.
- It lists the methods a type must provide, without saying how.
ArrayList,HashSet, and the rest fill in the code. - Map is not a Collection. It holds key-value pairs, so it sits on its own branch.
Because they all share this contract, they share a big set of methods. Learn the methods once and you know every collection.
🪜 The hierarchy: Iterable to Collection to the rest
At the top sits Iterable. Below it comes Collection. From Collection branch off List, Set, and Queue. Map lives on a separate branch.
Here is the shape in plain text.
Iterable └── Collection ├── List (ordered, duplicates allowed) ├── Set (no duplicates) └── Queue (first-in-first-out)
Map (key-value pairs, separate branch)Two points worth knowing:
Iterableis the parent ofCollection. It is what letsfor (String s : myCollection)work on any List, Set, or Queue.Collectionadds the real working methods on top:add,remove,size, and the rest.Iterableonly promises you can loop.
You rarely create an Iterable or Collection directly. But you often declare a variable as one, and you will see why in a moment.
🛠️ The methods every Collection has
Because List, Set, and Queue all extend Collection, they share these methods. The ones you will use every day:
add(item)adds an item. Returnstrueif the collection changed.remove(item)removes one matching item. Returnstrueif something was removed.contains(item)returnstrueif the item is present.size()returns how many items are in the collection.isEmpty()returnstrueif there are no items.clear()removes everything.addAll(other)adds every item from another collection.removeAll(other)removes every item that is also in the other collection.retainAll(other)keeps only items that are also in the other collection.iterator()gives you an object to walk through items one by one.stream()opens a stream for modern, pipeline-style processing.toArray()copies the items into a plain array.
You get all of this just by holding a Collection reference, even when the real object is an ArrayList.
🎯 Program to the interface
Declare your variable using the interface, not the concrete class. The code below stores an ArrayList, but the variable type is Collection.
import java.util.ArrayList;import java.util.Collection;
public class Demo { public static void main(String[] args) { Collection<String> fruits = new ArrayList<>(); fruits.add("apple"); fruits.add("banana"); fruits.add("cherry");
System.out.println("Size: " + fruits.size()); System.out.println("Has banana? " + fruits.contains("banana")); System.out.println(fruits); }}Line by line:
Collection<String> fruits = new ArrayList<>();declares aCollectionbut builds anArrayList. This is programming to the interface.addputs three strings in, one at a time.size()reports how many items are stored.contains("banana")checks for one specific item.
The output looks like this.
Output
Size: 3Has banana? true[apple, banana, cherry]Why declare it as Collection instead of ArrayList? Because tomorrow a HashSet might fit better. You change one word, new ArrayList<>() becomes new HashSet<>(), and the rest of your code keeps working. Your code depends on the contract, not one class.
🔁 Looping and the common methods together
This program adds some scores, checks them, removes one, and loops through the rest. Notice we never mention ArrayList after the first line.
import java.util.ArrayList;import java.util.Collection;
public class Scores { public static void main(String[] args) { Collection<Integer> scores = new ArrayList<>(); scores.add(90); scores.add(75); scores.add(60);
System.out.println("Is it empty? " + scores.isEmpty()); System.out.println("Total scores: " + scores.size());
scores.remove(75); // removes the value 75 System.out.println("After removing 75: " + scores);
// Loop works because Collection is Iterable int sum = 0; for (int score : scores) { sum = sum + score; } System.out.println("Sum: " + sum); }}What each part does:
isEmpty()returnsfalsehere, because we added three items.size()reports the count, which is three.remove(75)takes out the value 75 by matching it.- The for-each loop walks every remaining item, because Collection extends
Iterable.
The output looks like this.
Output
Is it empty? falseTotal scores: 3After removing 75: [90, 60]Sum: 150Watch out with Integer and remove
For a collection of Integer, calling remove(75) removes the value 75. There is a separate index-based remove on List, but plain Collection has no index. So on a Collection reference, remove always means “remove this item”, never “remove the item at this position”.
📦 Bulk operations: addAll, removeAll, retainAll
Sometimes you work with whole groups at once. The Collection interface gives you three bulk operations for that. The program below combines and compares two groups of languages.
import java.util.ArrayList;import java.util.Collection;import java.util.Arrays;
public class BulkDemo { public static void main(String[] args) { Collection<String> known = new ArrayList<>(Arrays.asList("Java", "Python")); Collection<String> wanted = new ArrayList<>(Arrays.asList("Python", "Go", "Rust"));
// addAll: add everything from another collection Collection<String> all = new ArrayList<>(known); all.addAll(wanted); System.out.println("After addAll: " + all);
// retainAll: keep only items also in wanted (the overlap) Collection<String> overlap = new ArrayList<>(known); overlap.retainAll(wanted); System.out.println("Overlap (retainAll): " + overlap);
// removeAll: drop items that are also in wanted Collection<String> onlyKnown = new ArrayList<>(known); onlyKnown.removeAll(wanted); System.out.println("Only known (removeAll): " + onlyKnown); }}The three operations:
addAll(wanted)pours every item fromwantedintoall. Both groups join. “Python” appears twice because this is a List.retainAll(wanted)keeps only items also inwanted. The overlap. Only “Python” survives.removeAll(wanted)deletes every item that appears inwanted. “Python” is dropped, leaving “Java”.
The output looks like this.
Output
After addAll: [Java, Python, Python, Go, Rust]Overlap (retainAll): [Python]Only known (removeAll): [Java]Think of these as set-style math. addAll is union, retainAll is intersection, removeAll is difference. Each returns true if the collection changed.
🔧 iterator, stream, and toArray
Three more methods each give you a different way to read everything. The program below shows all three on the same group of names.
import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;
public class ReadingDemo { public static void main(String[] args) { Collection<String> names = new ArrayList<>(); names.add("Alex"); names.add("Riya"); names.add("Sam");
// iterator: walk items one by one Iterator<String> it = names.iterator(); while (it.hasNext()) { System.out.println("iterator: " + it.next()); }
// stream: count names longer than 3 letters long longNames = names.stream() .filter(name -> name.length() > 3) .count(); System.out.println("Names longer than 3: " + longNames);
// toArray: copy into a plain array Object[] arr = names.toArray(); System.out.println("Array length: " + arr.length); }}What each method gives you:
iterator()hands back an object that walks the items withhasNext()andnext(). This is the engine behind the for-each loop.stream()opens a pipeline. Herefilterkeeps names longer than three letters, andcountreturns how many passed.toArray()copies the items into a plain array, useful when an older method expects an array.
The output looks like this.
Output
iterator: Alexiterator: Riyaiterator: Samiterator: Alex and Riya are longer than 3A quick correction on the output
Reading the code closely, “Alex” and “Riya” have four letters and “Sam” has three. So count returns 2, and the array length is 3. The real run prints Names longer than 3: 2 and Array length: 3 on the last two lines.
You will meet iterator properly in the next lesson. The point here is that all three methods belong to Collection, so every List, Set, and Queue offers them.
⚠️ Common Mistakes
A few Collection slip-ups to watch for.
- ❌ Confusing
CollectionwithCollections.Collection(no s) is the root interface.Collections(with an s) is a utility class of static helpers likeCollections.sort(). One is a contract, the other a toolbox.
Collection<String> c = new ArrayList<>(); // ✅ the interface, a typeCollections.sort(myList); // ✅ the utility class, a helper// Collection.sort(myList); // ❌ no such thing, wrong one- ❌ Expecting indexed access on a plain Collection. A
Collectionreference has noget(index). That method lives onList, not onCollection, because Sets and Queues have no index.
Collection<String> c = new ArrayList<>();c.add("apple");// String x = c.get(0); // ❌ does not compile, Collection has no getList<String> list = new ArrayList<>();String y = list.get(0); // ✅ get exists on List-
❌ Forgetting Map is not a Collection. You cannot pass a
Mapwhere aCollectionis expected. If you need its contents as a collection, usemap.keySet(),map.values(), ormap.entrySet(). -
❌ Assuming
removeuses an index. On aCollection,removeremoves a matching item, never the item at a position.
✅ Best Practices
Habits that pay off with collections.
- ✅ Program to the interface. Declare the broadest type that fits your needs, like
Collection<String> c = new ArrayList<>();. It keeps your code flexible and easy to change later. - ✅ Pick the right level. Use
Collectionwhen you only need add, remove, size, and looping. Step up toListonly when you truly need index access. - ✅ Accept
Collectionin method parameters. A method that takes aCollectioncan be called with a List, a Set, or a Queue. That is more reusable than one that demands anArrayList. - ✅ Use bulk operations instead of manual loops.
addAll,removeAll, andretainAllare clearer and shorter than writing the loop yourself. - ✅ Keep
CollectionandCollectionsstraight. Interface versus utility class. Read the finalscarefully.
🧩 What You’ve Learned
Nicely done. Let’s recap the Collection interface.
- ✅ Collection is the root interface for List, Set, and Queue, but not Map, which holds pairs on its own branch.
- ✅ The hierarchy runs Iterable to Collection to List, Set, and Queue, which is why every collection can be looped with a for-each.
- ✅ Every Collection shares methods like add, remove, contains, size, isEmpty, clear, iterator, stream, and toArray.
- ✅ Bulk operations addAll, removeAll, and retainAll act on whole groups, like union, difference, and intersection.
- ✅ Programming to the interface with
Collection<String> c = new ArrayList<>();keeps your code flexible, andCollectionis not the same as theCollectionsutility class.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
Which of these is NOT a sub-interface of Collection?
Why: Map holds key-value pairs on a separate branch, so it does not extend Collection. List, Set, and Queue all do.
- 2
What does it mean to program to the interface here?
Why: You declare the variable with the interface type, such as Collection, and build a concrete class like ArrayList, so the implementation is easy to swap later.
- 3
What is the difference between Collection and Collections?
Why: Collection (no s) is the root interface. Collections (with s) is a utility class with static helpers like sort and reverse.
- 4
What does retainAll do?
Why: retainAll keeps only the items that also appear in the other collection, which is the intersection of the two.
🚀 What’s Next?
You saw iterator() make a brief appearance above. Next we will study it properly, along with the Iterable interface that sits at the very top of the hierarchy. You will learn how the for-each loop really works under the hood, and how to remove items safely while looping.