Skip to content

Part 12 — Collections Utility Class Deep Dive

The Collections utility class is a helper class containing static methods that operate on collections.

A common interview question is:

What is the difference between Collection and Collections?

This is one of the easiest questions to get wrong.


1. Collection vs Collections

Collection Collections
Interface Utility class
Root interface of the Collections Framework Contains static utility methods
Implemented by List, Set, Queue Cannot be instantiated

Example:

Collection<String> c = new ArrayList<>();

vs.

Collections.sort(list);

2. Class Declaration

public class Collections {
    // static utility methods
}

Notice:

  • Final-like utility design (private constructor)
  • Cannot be instantiated
  • All methods are static

3. sort()

Example:

List<Integer> list =
    Arrays.asList(5, 3, 1, 4);

Collections.sort(list);

System.out.println(list);

Output:

[1, 3, 4, 5]

Internally (modern JDK):

Collections.sort()

↓

List.sort()

↓

TimSort

4. Custom Sorting

Collections.sort(
    employees,
    Comparator.comparing(Employee::getSalary)
);

Equivalent modern syntax:

employees.sort(
    Comparator.comparing(Employee::getSalary)
);

5. binarySearch()

Interview favorite.

Example:

List<Integer> list =
    Arrays.asList(10,20,30,40,50);

int index =
    Collections.binarySearch(list,30);

System.out.println(index);

Output:

2

Important

The collection must already be sorted.

Wrong:

40 10 20 30

Correct:

10 20 30 40

Otherwise, the result is undefined.


6. How Binary Search Works

Example:

10 20 30 40 50

Search:

40

Steps:

Middle = 30

↓

40 > 30

↓

Search right half

↓

Found

Complexity:

O(log n)

For ArrayList.


7. reverse()

Example:

Collections.reverse(list);

Before:

A B C D

After:

D C B A

Complexity:

O(n)

8. shuffle()

Randomizes order.

Collections.shuffle(list);

Example:

Before:

1 2 3 4 5

Possible result:

4 1 5 2 3

Common uses:

  • Games
  • Random sampling
  • Card decks

9. swap()

Example:

Collections.swap(list,0,3);

Before:

A B C D

After:

D B C A

10. rotate()

Moves elements cyclically.

Example:

Collections.rotate(list,2);

Before:

A B C D E

After:

D E A B C

Useful for:

  • Circular buffers
  • Scheduling
  • Round-robin algorithms

11. frequency()

Counts occurrences.

Collections.frequency(list,"Java");

Example:

Java

Spring

Java

Kafka

Result:

2

Complexity:

O(n)

12. min() and max()

Example:

Collections.min(numbers);

Collections.max(numbers);

Output:

Minimum

Maximum

Custom comparator:

Collections.max(
    employees,
    Comparator.comparing(Employee::getSalary)
);

13. fill()

Replaces every element.

Collections.fill(list,"Java");

Before:

A B C

After:

Java Java Java

14. copy()

Example:

Collections.copy(destination, source);

Important:

Destination must already have enough elements.

Wrong:

List<String> dest =
    new ArrayList<>();

Throws:

IndexOutOfBoundsException

Correct:

List<String> dest =
    new ArrayList<>(
        Arrays.asList("", "", "")
    );

Collections.copy(dest, source);

15. replaceAll()

Example:

Collections.replaceAll(
    list,
    "Java",
    "Spring"
);

Before:

Java

Python

Java

After:

Spring

Python

Spring

16. disjoint()

Checks whether two collections share any elements.

Collections.disjoint(a,b);

Returns:

true

if they have no common elements.


17. singletonList()

Creates an immutable list with one element.

List<String> list =
    Collections.singletonList("Java");

Result:

[Java]

Immutable.


18. Empty Collections

Useful factory methods:

Collections.emptyList()

Collections.emptySet()

Collections.emptyMap()

Advantages:

  • Immutable
  • Reusable singleton instances
  • Avoid returning null

Recommended API design:

return Collections.emptyList();

instead of:

return null;

19. synchronizedList()

Thread-safe wrapper.

List<String> list =
    Collections.synchronizedList(
        new ArrayList<>()
    );

Internally:

Single lock

↓

Every operation synchronized

Important

Iteration still requires external synchronization.

Correct:

synchronized (list) {
    for (String s : list) {
        System.out.println(s);
    }
}

Otherwise, concurrent modification may still cause problems.


20. unmodifiableList()

Creates a read-only view.

List<String> view =
    Collections.unmodifiableList(list);

Trying:

view.add("Java");

Throws:

UnsupportedOperationException

Remember:

The original list can still change.


21. Time Complexity

Method Complexity
sort O(n log n)
binarySearch O(log n) on random-access lists
reverse O(n)
shuffle O(n)
rotate O(n)
frequency O(n)
min O(n)
max O(n)

Interview note: On a LinkedList, Collections.binarySearch() is not O(log n) overall because random access is O(n). The JDK adapts its implementation, but binary search is most effective on random-access lists such as ArrayList.


Production Examples

Sort Employees

employees.sort(
    Comparator.comparing(Employee::getSalary)
);

Randomize Quiz Questions

Collections.shuffle(questions);

API Response

Instead of:

return null;

Use:

return Collections.emptyList();

Safer for callers.


Read-Only Configuration

List<String> config =
    Collections.unmodifiableList(settings);

Common Interview Questions

Q1. Difference between Collection and Collections?

Collection Collections
Interface Utility class

Q2. Which sorting algorithm does Collections.sort() use?

Modern JDKs delegate to List.sort(), which uses TimSort for object sorting.


Q3. Can binarySearch() work on an unsorted list?

No.

The list must be sorted according to the same ordering used for searching.


Q4. Difference between List.of() and Collections.unmodifiableList()?

List.of() unmodifiableList()
Truly immutable Read-only view
No backing mutable collection Backed by another collection

Q5. Why return Collections.emptyList() instead of null?

It avoids unnecessary null checks and reduces the risk of NullPointerException.


Q6. Is Collections.synchronizedList() the same as CopyOnWriteArrayList?

No.

synchronizedList CopyOnWriteArrayList
Single lock Copy-on-write
Better for frequent writes Better for read-heavy workloads

Q7. Can you modify a collection returned by Collections.singletonList()?

No.

It is immutable.


Q8. Does Collections.unmodifiableList() make the original list immutable?

No.

Only the wrapper is read-only.


Q9. Why does Collections.copy() throw IndexOutOfBoundsException?

Because it replaces existing elements; it does not grow the destination list.


Q10. When would you use Collections.disjoint()?

To efficiently check whether two collections have no common elements.


Senior Interview Scenario

Question:

Why is this bad API design?

public List<User> getUsers() {

    return null;
}

Strong Answer:

Returning null forces every caller to perform null checks and increases the risk of NullPointerException.

A better implementation is:

return Collections.emptyList();

This clearly indicates "no results" while allowing callers to iterate safely without additional checks.


Key Takeaways

  • Collection is an interface; Collections is a utility class.
  • Collections.sort() delegates to List.sort() in modern JDKs.
  • binarySearch() requires a sorted collection.
  • Collections.emptyList() is preferred over returning null.
  • Collections.unmodifiableList() creates a read-only view, not an immutable collection.
  • Collections.synchronizedList() provides thread safety through a single lock but still requires external synchronization during iteration.
  • Utility methods like reverse(), shuffle(), rotate(), min(), and max() are widely used in production code.

Next: Part 13 — Performance & Memory Tuning

We'll cover:

  • Big-O analysis of all major collections
  • Memory layout and object overhead
  • Initial capacity tuning
  • Load factor tuning
  • GC impact
  • Cache locality
  • Choosing the right collection for production workloads
  • Performance optimization strategies
  • Senior-level interview questions