This part compares the List and Set classes you use every day: ArrayList against Vector and LinkedList, the three cursors (Iterator, ListIterator, Enumeration), HashSet, LinkedHashSet and TreeSet, and finally Comparable and Comparator. There is also a short look at the legacy classes and at what Java 1.4 added.
Many of these questions are asked as "difference between X and Y", so I have used small tables where a comparison helps. Do not just memorise the rows. For each one, be ready to say which you would pick for a given problem and why, since that is the follow-up you will usually get.
Q1. How is ArrayList different from Vector?
| ArrayList | Vector | |
|---|---|---|
| Thread safety | Not synchronized | Its methods are synchronized |
| Speed in one thread | Faster | Slower, because of locking |
| Growth when full | About 1.5 times | Doubles by default |
| Since | Java 1.2 (collections framework) | Java 1.0 (legacy) |
Vector's per-method locking does not make compound actions like "check then add" safe anyway. For a shared list today, use Collections.synchronizedList() or CopyOnWriteArrayList, and ArrayList everywhere else.
Q2. When would you choose ArrayList over LinkedList, and the other way round?
| ArrayList | LinkedList | |
|---|---|---|
| Storage | Resizable array | Doubly linked nodes |
| get(i) | O(1) | O(n), walks from the nearer end |
| Add or remove at the ends | O(1) at the end (amortised), O(n) at the front | O(1) at both ends |
| Interfaces | List, RandomAccess | List, Deque (no RandomAccess) |
| Memory | Compact | Extra node object with two links per element |
The textbook line says LinkedList is better for inserting in the middle, but you first have to walk to that position, which is O(n). In practice ArrayList wins for most workloads because its data sits together in memory. Use LinkedList only when you mainly add and remove at the ends, and even then ArrayDeque is usually faster.
Q3. What is the difference between the size and the capacity of a collection?
Size is how many elements the collection currently holds; size() returns it. Capacity is how many elements the internal array can hold before it has to grow. An ArrayList with 3 elements might have capacity 10. When size reaches capacity, a bigger array is allocated and the elements are copied over.
Capacity only applies to array-based or hash-based classes. If you know you will add 10,000 items, new ArrayList<>(10_000) avoids repeated resizing. ensureCapacity() and trimToSize() let you adjust it.
Q4. Which classes and interfaces in java.util are considered legacy?
The ones that existed before the collections framework arrived in Java 1.2:
- Enumeration (interface)
- Dictionary (abstract class)
- Hashtable, which extends Dictionary
- Properties, which extends Hashtable
- Vector
- Stack, which extends Vector
They were retrofitted to implement List or Map, so they still work with the framework. Properties is still used for config files. For the rest, prefer ArrayList, HashMap or ConcurrentHashMap, and ArrayDeque instead of Stack.
Q5. Compare Iterator and ListIterator.
| Iterator | ListIterator | |
|---|---|---|
| Works on | Any Collection | Only List implementations |
| Direction | Forward only | Forward and backward |
| Operations | hasNext(), next(), remove() | Also hasPrevious(), previous(), nextIndex(), set(), add() |
| How to get it | collection.iterator() | list.listIterator() or listIterator(index) |
List<String> langs = new ArrayList<>(List.of("java", "c", "python"));
ListIterator<String> it = langs.listIterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("c")) it.set("cpp");
if (s.equals("python")) it.add("go");
}
System.out.println(langs); // [java, cpp, python, go]
while (it.hasPrevious()) System.out.print(it.previous() + " "); // go python cpp java
Q6. How does Enumeration differ from Iterator?
| Enumeration | Iterator | |
|---|---|---|
| Since | Java 1.0, legacy | Java 1.2 |
| Available on | Vector, Hashtable and a few old APIs | Every Collection |
| Remove while iterating | Not possible | remove() |
| Method names | hasMoreElements(), nextElement() | hasNext(), next() |
| Obtained by | elements() | iterator() |
Since Java 9, Enumeration has asIterator(), and Collections.list() turns one into an ArrayList, which helps when an old API hands you an Enumeration.
Q7. Are enum and Enumeration related?
No, they only share a name. An enum (Java 5) is a special kind of class that defines a fixed set of named constants, such as enum Size { SMALL, MEDIUM, LARGE }. Enums can have fields, constructors and methods, and work well in switch.
Enumeration is an old interface for stepping through elements of a legacy collection one at a time. One is a type definition, the other is a cursor.
Q8. What are the drawbacks of Enumeration?
- It can only read; there is no way to remove the current element.
- It moves forward only.
- It is available only from legacy classes and a handful of old APIs, so it is not a universal cursor.
- Its method names are long, which is part of why Iterator replaced it.
These limits are exactly what Iterator and ListIterator were designed to fix.
Q9. What did Java 1.4 add to the collections framework?
The main additions were LinkedHashMap and LinkedHashSet, which keep insertion order, and IdentityHashMap, which compares keys with == instead of equals(). The RandomAccess marker interface also arrived in 1.4, so algorithms can check whether a list supports fast indexed access.
The much bigger change came in Java 5, with generics, the enhanced for loop, and the java.util.concurrent package.
Q10. How are ListIterator and Iterator related in the type hierarchy?
ListIterator extends Iterator. So every ListIterator is also an Iterator and can be used wherever an Iterator is expected. It inherits hasNext(), next() and remove(), and adds the list-specific methods covered in Q5.
Q11. What are the main features of HashSet?
- It implements Set, so duplicates are not stored. Duplicates are detected with hashCode() and equals().
- Internally it is backed by a HashMap; your elements are the keys and a shared dummy object is the value.
- It allows one null element.
- Iteration order is not defined and can change as the set grows.
- add(), remove() and contains() are O(1) on average.
- It is not synchronized, and it is Serializable and Cloneable.
If you put your own objects in a HashSet, override equals() and hashCode() together, or a record does it for you.
Q12. What is LinkedHashSet and how does it keep order?
LinkedHashSet is a subclass of HashSet. Internally it is backed by a LinkedHashMap, which is a hash table plus a doubly linked list running through all entries. The hash table gives fast lookups and the linked list remembers the order in which elements were inserted, so iteration follows insertion order.
Since Java 21 it implements SequencedSet, so you get getFirst(), getLast() and reversed() directly.
Q13. What happens if you add a duplicate element to a Set?
Nothing breaks. add() simply returns false and the set stays unchanged. There is no compile-time error and no exception.
Set<String> cities = new LinkedHashSet<>();
System.out.println(cities.add("Pune")); // true
System.out.println(cities.add("Delhi")); // true
System.out.println(cities.add("Pune")); // false
System.out.println(cities); // [Pune, Delhi]
Checking the return value is a neat way to detect duplicates in one pass over a list.
Q14. Compare HashSet and LinkedHashSet.
| HashSet | LinkedHashSet | |
|---|---|---|
| Backed by | HashMap | LinkedHashMap (hash table plus linked list) |
| Iteration order | Not defined | Insertion order |
| Memory | Less | A little more, for the links |
| Since | Java 1.2 | Java 1.4 |
Q15. When should you pick LinkedHashSet instead of HashSet?
Pick it whenever the order of output matters to you or to your users. Common cases: removing duplicates from a list while keeping the first occurrence of each item, showing "recently seen" items in the order they arrived, or getting a predictable order in tests and logs.
If order truly does not matter, HashSet uses a bit less memory. Lookups are O(1) on average for both.
Q16. What are the main features of TreeSet?
- It keeps elements sorted, either by their natural order (Comparable) or by a Comparator you pass in.
- Internally it is backed by a TreeMap, which is a red-black tree, so add, remove and contains are O(log n).
- Duplicates are not stored. "Duplicate" here means compareTo() or compare() returns 0, not equals().
- Elements must be mutually comparable; mixing types like String and Integer throws ClassCastException.
- null is not allowed with natural ordering. Old answers say an empty TreeSet accepts null as its first element; that stopped being true in Java 7, and now even the first add(null) throws NullPointerException.
- It implements NavigableSet, so you get first(), last(), floor(), ceiling(), headSet() and tailSet().
Q17. What separates List from Set?
| List | Set | |
|---|---|---|
| Duplicates | Allowed | Not allowed |
| Order | Always keeps a position for each element | Depends on the class: none (HashSet), insertion (LinkedHashSet) or sorted (TreeSet) |
| Index access | get(int), set(int, E) | No indexes |
| Main classes | ArrayList, LinkedList, Vector, Stack | HashSet, LinkedHashSet, TreeSet |
Q18. What is the Comparable interface?
Comparable<T> lets a class define its natural ordering, the default way its objects are sorted. It lives in java.lang and has one method, int compareTo(T other), returning a negative number, zero or a positive number for less than, equal and greater than. String, Integer and LocalDate all implement it, which is why Collections.sort() works on them directly.
Try to keep compareTo() consistent with equals(), otherwise sorted sets and maps may treat two unequal objects as duplicates.
Q19. What is the Comparator interface?
Comparator<T> defines an ordering outside the class, so you can sort the same objects in many ways, or sort classes you cannot modify. It lives in java.util. Its one abstract method is int compare(T a, T b). It also declares equals(Object), but that is just Object's method restated, so Comparator is still a functional interface and can be a lambda.
Java 8 added static and default helpers such as comparing(), comparingInt(), thenComparing(), reversed() and nullsFirst(), which build comparators without writing compare() at all.
Q20. Compare Comparable and Comparator.
| Comparable | Comparator | |
|---|---|---|
| Purpose | One natural order | Any number of custom orders |
| Package | java.lang | java.util |
| Method | compareTo(T other) | compare(T a, T b) |
| Where it lives | Inside the class being sorted | Separate object, often a lambda |
Neither is a marker interface; both declare a method you must implement. Here is a Student record with a natural order by name and a separate comparator by marks (highest first), then name:
record Student(String name, int marks) implements Comparable<Student> {
public int compareTo(Student other) {
return name.compareTo(other.name);
}
}
List<Student> list = new ArrayList<>(List.of(
new Student("Riya", 88), new Student("Arjun", 75), new Student("Kabir", 88)));
Collections.sort(list); // Arjun, Kabir, Riya
list.sort(Comparator.comparingInt(Student::marks).reversed()
.thenComparing(Student::name)); // Kabir, Riya, Arjun
Quick revision
- ArrayList is the default list; Vector is legacy and slower.
- LinkedList rarely beats ArrayList; for queues use ArrayDeque.
- Size is what you have, capacity is what fits before a resize.
- Set.add() returns false for a duplicate instead of throwing.
- HashSet has no order, LinkedHashSet keeps insertion order, TreeSet keeps sorted order.
- Comparable gives one natural order; Comparator gives as many as you need.
Frequently asked questions
How do I practise collections questions effectively?
Pick a small dataset, like a list of students, and solve the same task with different collections: remove duplicates, keep order, sort by two fields. Seeing the differences in output teaches more than reading tables.
Do interviewers still ask about Vector and Enumeration?
Yes, mostly as comparison questions. Give the difference quickly, then say what you would use in new code. That last line is what separates a prepared answer from a memorised one.
What is the most common coding task on Comparator?
Sorting a list of objects by one field descending and another ascending. Practise writing it with Comparator.comparing() and thenComparing() until you can do it without looking anything up.
← Previous: Part 1 | Next: Part 3 →
See everything in one place: Interview Preparation Hub
Comments
Post a Comment