Backend Systemsbeginner
Java Collections, Generics & Streams API
Master Java's collection framework: List, Map, Set, Queue. Write type-safe generics. Use Streams for functional-style data transformations.
Asma HafeezApril 17, 20266 min read
javacollectionsgenericsstreamslambda
Java Collections, Generics & Streams API
Java's collection framework and Streams API turn complex data manipulation into readable, composable pipelines.
The Collections Framework
All collections live in java.util. Import them as needed.
List — Ordered, allows duplicates
JAVA
import java.util.ArrayList;
import java.util.List;
// Create
List<String> names = new ArrayList<>();
List<String> fixed = List.of("Alice", "Bob", "Carol"); // immutable
// Add
names.add("Alice");
names.add("Bob");
names.add(0, "Zara"); // insert at index 0
// Access
String first = names.get(0); // "Zara"
int size = names.size(); // 3
boolean has = names.contains("Bob"); // true
// Remove
names.remove("Alice"); // by value
names.remove(0); // by index
// Iterate
for (String name : names) {
System.out.println(name);
}
// Sort
names.sort(null); // natural order
names.sort((a, b) -> b.compareTo(a)); // reverse alphabeticalMap — Key-value pairs, unique keys
JAVA
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
// Put
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Alice", 98); // overwrites existing
// Get
int aliceScore = scores.get("Alice"); // 98
int defaultScore = scores.getOrDefault("Zara", 0); // 0
// Check
boolean hasKey = scores.containsKey("Bob"); // true
// Remove
scores.remove("Bob");
// Iterate
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// Functional update
scores.merge("Alice", 5, Integer::sum); // 98 + 5 = 103
scores.computeIfAbsent("Carol", k -> 0); // add Carol with 0 if missingSet — Unique elements, no duplicates
JAVA
import java.util.HashSet;
import java.util.Set;
Set<String> visited = new HashSet<>();
visited.add("page1");
visited.add("page2");
visited.add("page1"); // no-op — already exists
System.out.println(visited.size()); // 2
System.out.println(visited.contains("page1")); // true
// Set operations
Set<Integer> a = new HashSet<>(Set.of(1, 2, 3));
Set<Integer> b = new HashSet<>(Set.of(2, 3, 4));
a.retainAll(b); // intersection: {2, 3}
a.addAll(b); // union: {2, 3, 4}
a.removeAll(b); // difference: {1}Queue and Deque
JAVA
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Deque;
Queue<String> queue = new ArrayDeque<>();
queue.offer("first");
queue.offer("second");
String head = queue.poll(); // "first" — removes
String peek = queue.peek(); // "second" — doesn't remove
Deque<String> stack = new ArrayDeque<>();
stack.push("first");
stack.push("second");
String top = stack.pop(); // "second" (LIFO)Generics
Generics let you write type-safe, reusable code.
JAVA
// A generic container
public class Box<T> {
private T value;
public Box(T value) {
this.value = value;
}
public T get() { return value; }
public void set(T value) { this.value = value; }
@Override
public String toString() { return "Box[" + value + "]"; }
}
Box<String> stringBox = new Box<>("hello");
Box<Integer> intBox = new Box<>(42);
System.out.println(stringBox.get().toUpperCase()); // HELLO
System.out.println(intBox.get() * 2); // 84Generic Methods
JAVA
// Works with any Comparable type
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
System.out.println(max(3, 7)); // 7
System.out.println(max("apple", "banana")); // bananaBounded Type Parameters
JAVA
// Only accept Number subtypes (Integer, Double, etc.)
public static <T extends Number> double sum(List<T> numbers) {
double total = 0;
for (T n : numbers) {
total += n.doubleValue();
}
return total;
}
List<Integer> ints = List.of(1, 2, 3, 4, 5);
System.out.println(sum(ints)); // 15.0Streams API
Streams transform collections using a pipeline of operations. They are lazy — operations execute only when a terminal operation is called.
JAVA
import java.util.stream.Collectors;
import java.util.stream.Stream;
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// filter → map → collect
List<Integer> evenSquares = numbers.stream()
.filter(n -> n % 2 == 0) // keep even numbers
.map(n -> n * n) // square them
.collect(Collectors.toList()); // [4, 16, 36, 64, 100]Common Intermediate Operations
JAVA
List<String> names = List.of("Alice", "Bob", "Carol", "Alice", "Dave");
// filter — keep matching elements
List<String> longNames = names.stream()
.filter(n -> n.length() > 4)
.toList(); // ["Alice", "Carol", "Alice"]
// map — transform each element
List<String> upper = names.stream()
.map(String::toUpperCase)
.toList(); // ["ALICE", "BOB", ...]
// distinct — remove duplicates
List<String> unique = names.stream()
.distinct()
.toList(); // ["Alice", "Bob", "Carol", "Dave"]
// sorted — natural or custom order
List<String> sorted = names.stream()
.sorted()
.toList();
// limit / skip
List<Integer> first3 = numbers.stream().limit(3).toList(); // [1, 2, 3]
List<Integer> after3 = numbers.stream().skip(3).toList(); // [4, 5, ...]
// flatMap — flatten nested collections
List<List<Integer>> nested = List.of(List.of(1, 2), List.of(3, 4));
List<Integer> flat = nested.stream()
.flatMap(List::stream)
.toList(); // [1, 2, 3, 4]Common Terminal Operations
JAVA
List<Integer> nums = List.of(3, 1, 4, 1, 5, 9, 2, 6);
// count
long count = nums.stream().filter(n -> n > 3).count(); // 4
// sum, min, max, average
int sum = nums.stream().mapToInt(Integer::intValue).sum(); // 31
OptionalInt max = nums.stream().mapToInt(Integer::intValue).max(); // 9
double avg = nums.stream().mapToInt(Integer::intValue).average().orElse(0); // 3.875
// findFirst, findAny
Optional<Integer> first = nums.stream().filter(n -> n > 5).findFirst(); // 9
// anyMatch, allMatch, noneMatch
boolean anyBig = nums.stream().anyMatch(n -> n > 8); // true
boolean allPos = nums.stream().allMatch(n -> n > 0); // true
boolean noneNeg = nums.stream().noneMatch(n -> n < 0); // true
// reduce — fold to a single value
int product = nums.stream().reduce(1, (a, b) -> a * b); // 3*1*4*1*5*9*2*6
// joining strings
String joined = Stream.of("Alice", "Bob", "Carol")
.collect(Collectors.joining(", ")); // "Alice, Bob, Carol"Collecting to Maps and Groups
JAVA
List<String> words = List.of("apple", "banana", "cherry", "avocado", "blueberry");
// Group by first letter
Map<Character, List<String>> grouped = words.stream()
.collect(Collectors.groupingBy(w -> w.charAt(0)));
// {'a': ["apple", "avocado"], 'b': ["banana", "blueberry"], 'c': ["cherry"]}
// Count by first letter
Map<Character, Long> counts = words.stream()
.collect(Collectors.groupingBy(w -> w.charAt(0), Collectors.counting()));
// {'a': 2, 'b': 2, 'c': 1}
// To Map
Map<String, Integer> wordLengths = words.stream()
.collect(Collectors.toMap(w -> w, String::length));
// {"apple": 5, "banana": 6, ...}Lambda Expressions
Lambdas are anonymous functions used with functional interfaces.
JAVA
// Functional interface (one abstract method)
@FunctionalInterface
interface Transformer<T, R> {
R transform(T input);
}
Transformer<String, Integer> lengthFn = s -> s.length();
System.out.println(lengthFn.transform("hello")); // 5
// Common functional interfaces from java.util.function
import java.util.function.*;
Function<String, Integer> toLength = String::length; // T → R
Predicate<String> isLong = s -> s.length() > 5; // T → boolean
Consumer<String> printer = System.out::println; // T → void
Supplier<String> greeting = () -> "Hello!"; // () → T
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;Key Takeaways
- Use
List.of(),Set.of(),Map.of()for immutable collections — safer by default HashMapis unordered — useLinkedHashMapto preserve insertion order orTreeMapfor sorted keys- Stream pipelines are lazy — nothing runs until you call a terminal operation
maptransforms one type to another;flatMapflattens nested streams- Method references (
String::length,System.out::println) make streams more readable
Enjoyed this article?
Explore the Backend Systems learning path for more.
Found this helpful?
Leave a comment
Have a question, correction, or just found this helpful? Leave a note below.