List / ArrayList
java.util.List is the interface every list-like collection implements: ArrayList (random access, dense), LinkedList (rare in modern Java; reach for ArrayDeque instead), and the immutable List.of(...). Most day-to-day work is on ArrayList plus the Stream API — pick the right one and the rest of your code stays clean.
List operations, immutability, and streams
EXAMPLE
import java.util.*;
import java.util.stream.*;
public class ListsDemo {
public static void main(String[] args) {
// 1) Mutable ArrayList — the default
List<Integer> nums = new ArrayList<>(List.of(3, 1, 4, 1, 5, 9, 2, 6));
nums.add(5);
nums.remove(Integer.valueOf(1)); // remove by value (note the boxing)
nums.set(0, 99); // replace at index
System.out.println(nums);
// 2) Immutable List.of — throws on any mutation
List<String> tags = List.of("alpha", "beta", "gamma");
try { tags.add("delta"); }
catch (UnsupportedOperationException e) {
System.out.println("List.of is immutable: " + e.getMessage());
}
// 3) Defensive copies — return immutable views from APIs
List<String> safe = List.copyOf(new ArrayList<>(tags));
// returns an immutable copy, even if the input is mutable
// 4) Sorting — natural and custom
List<String> people = new ArrayList<>(List.of("alice", "charlie", "bob"));
Collections.sort(people); // natural order
people.sort(Comparator.comparingInt(String::length).reversed());
// 5) Search — binarySearch on a SORTED list, O(log n)
Collections.sort(people);
int idx = Collections.binarySearch(people, "bob");
System.out.println("bob at index " + idx);
// 6) Streams — filter/map/reduce without writing a loop
int evenSquares = nums.stream()
.filter(n -> n % 2 == 0)
.mapToInt(n -> n * n)
.sum();
System.out.println("sum of even squares: " + evenSquares);
// 7) Collect to a NEW immutable list (Java 16+)
List<String> upper = people.stream()
.map(String::toUpperCase)
.toList();
System.out.println(upper);
// 8) Group-by — Map<K, List<V>> in one line
List<String> words = List.of("ant", "ape", "bear", "bat", "cat");
Map<Character, List<String>> byFirst = words.stream()
.collect(Collectors.groupingBy(w -> w.charAt(0)));
System.out.println(byFirst);
// 9) Partitioning into two buckets
Map<Boolean, List<Integer>> parts = nums.stream()
.collect(Collectors.partitioningBy(n -> n > 4));
System.out.println(parts);
// 10) Iterate without indices (cleanest), or with indices when you need them
for (var word : words) System.out.print(word + " ");
System.out.println();
for (int i = 0; i < words.size(); i++) {
System.out.println(i + " -> " + words.get(i));
}
}
}
Why it matters
Use ArrayList for everything until benchmarks tell you otherwise. LinkedList wins only when you insert/remove at both ends millions of times AND never index — and ArrayDeque is faster for that case anyway. The mental model "LinkedList is good for inserts" predates modern CPU caches and is wrong on real hardware.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
List<Integer> xs = new ArrayList<>(); xs.add(1); xs.add(2); xs.add(3); System.out.println(xs.get(0)); System.out.println(xs.size());Try it Yourself »
Discussion
Loading…