Skip to main content

Collections and Generics

The Collections Framework​

InterfaceImplementationsCharacteristics
ListArrayList, LinkedListOrdered, allows duplicates
SetHashSet, LinkedHashSet, TreeSetNo duplicates
MapHashMap, LinkedHashMap, TreeMapKey-value pairs
Queue / DequeArrayDeque, PriorityQueue, LinkedListFIFO / double-ended / priority
import java.util.*;

List<String> names = new ArrayList<>();
names.add("Asha");
names.add("Ravi");
Collections.sort(names);

Set<Integer> unique = new HashSet<>(List.of(1, 2, 2, 3)); // [1, 2, 3]

Map<String, Integer> marks = new HashMap<>();
marks.put("Asha", 91);
marks.merge("Asha", 5, Integer::sum); // 96
for (Map.Entry<String, Integer> e : marks.entrySet()) {
System.out.println(e.getKey() + " -> " + e.getValue());
}

Complexity cheat sheet​

StructureAccess / lookupInsertNotes
ArrayListO(1) by indexO(1) amortised at endDynamic array
LinkedListO(n)O(1) at known nodeRarely the best choice
HashMap / HashSetO(1) averageO(1) averageUnordered
TreeMap / TreeSetO(log n)O(log n)Sorted
PriorityQueueO(1) peekO(log n)Binary heap

Generics​

Generics provide compile-time type safety and remove casts.

public class Box<T> {
private T value;
public Box(T value) { this.value = value; }
public T get() { return value; }
}

Box<String> b = new Box<>("hello");
String s = b.get(); // no cast needed

static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}

Streams​

import java.util.stream.*;

List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);

int sumOfSquaresOfEvens = nums.stream()
.filter(n -> n % 2 == 0)
.mapToInt(n -> n * n)
.sum(); // 4 + 16 + 36 = 56

List<String> upper = Stream.of("a", "b").map(String::toUpperCase).collect(Collectors.toList());
TIP

Use the interface type on the left (List<String> xs = new ArrayList<>()) so the implementation can change without touching the rest of the code.