List
In short: A collections interface for ordered, indexed collections that allow duplicates — the two most important implementations are ArrayList and LinkedList.
In more detail: Unlike Set, a List preserves insertion order and allows targeted access via an index (list.get(0)). Which concrete implementation is worthwhile depends on the access pattern: lots of reading by index → ArrayList, lots of inserting/removing in the middle of the list → LinkedList.
In Depth
List<String> names = new ArrayList<>(); // interface type on the left, concrete implementation on the right
names.add("Anna");
names.add("Ben");
names.add(0, "First");
List<String> immutable = List.of("Fix", "One", "Two"); // read-only, throws on add()
// Interface-based declaration allows swapping the implementation
List<String> switchTest = new LinkedList<>(); // identical code works exactly the sameThe convention of always programming against the INTERFACE (List) instead of the concrete class (ArrayList) is one of the most important Java style principles: calling code only cares about what List promises (add, get, remove, …), and is thus independent of which concrete implementation actually sits behind it. If the access pattern changes later (e.g. from lots of reading to lots of inserting in the middle), new ArrayList<>() can simply be replaced with new LinkedList<>(), without having to touch the rest of the code — exactly the principle of abstraction in practice. List.of(...) (since Java 9) creates an immutable list, useful for fixed value collections that never need to change.
Common operations at a glance
List<Integer> numbers = new ArrayList<>(List.of(3, 1, 4, 1, 5));
numbers.sort(null); // sort ascending (natural order)
Collections.reverse(numbers); // put into reverse order
int index = numbers.indexOf(4); // position of the first occurrence, -1 if not found
List<Integer> sublist = numbers.subList(1, 3); // a slice, a LIVE view of the original!
numbers.removeIf(n -> n > 3); // filter functionally instead of manually iteratingAn important pitfall with subList(): the result isn’t a copy, but a VIEW on the same underlying memory — changes to the sublist directly affect the original list, and conversely, structural changes to the original list can invalidate the sublist (ConcurrentModificationException on the next access).
List vs. Array
A classic Java array (int[]) has a FIXED size and is more memory-efficient for primitive types, but can’t grow. A List grows dynamically with add(), but costs some overhead (for ArrayList, internally itself an array again, which is automatically reallocated and copied as needed once the capacity is exceeded). For generic types (List<String>), there’s no direct array alternative anyway, since Java technically doesn’t allow generic array creation (new String[]<T>).
See also: ArrayList, LinkedList, Collections, Arrays