Scala中List仅存不可变变体的原因探究(从Java视角出发)
Great question! As someone who came to Scala from Java, I totally get why this might feel confusing at first—let’s break it down step by step from a Java developer’s perspective.
If you’ve used Java, you’re familiar with mutable lists like ArrayList or LinkedList—they’re go-to for dynamic collections where you add/remove elements constantly. Scala takes a different approach here:
- Scala’s
Listis a functional-style singly linked list, which is inherently designed to be immutable. When you "modify" a Scala List (like adding an element), you’re actually creating a new List with the new element prepended—no changes to the original. This aligns perfectly with functional programming principles (no side effects, thread-safe by default), which was a big priority for Scala’s designers. - For mutable linear collections, Scala doesn’t duplicate Java’s
ArrayList—instead, it offersscala.collection.mutable.ArrayBuffer(which acts almost exactly like Java’sArrayList) andLinkedListin the mutable package. This avoids redundant functionality and keeps the coreListfocused on its functional, immutable use case.
When you write List(1,2,3) without new, you’re calling the immutable companion object—this is Scala’s way of pushing developers toward the safer, thread-friendly immutable collections by default, which solves a huge pain point in Java (where you have to jump through hoops like Collections.unmodifiableList() or Java 9+ List.of() to get true immutability).
Java’s standard library has always leaned heavily on mutable HashSet/HashMap, but true immutable Set/Map implementations were only added in Java 9 (with Set.of()/Map.of()). Before that, you had to use wrapper classes that still let you modify the underlying collection if you had a reference to it.
Scala fills this gap by providing both variants:
- Immutable Set/Map: The default when you write
Set(1,2,3)orMap("a"->1)—these are true immutable implementations, no hidden mutability. They’re perfect for functional code, concurrent systems, or any scenario where you don’t want unexpected changes to your collection. - Mutable Set/Map: Found in
scala.collection.mutable, these behave exactly like Java’sHashSet/HashMap—great for cases where you need frequent in-place modifications (like building a collection incrementally without creating tons of new objects).
Scala’s designers recognized that Set and Map are used in a wider range of scenarios than List—sometimes you need the safety of immutability, other times you need the performance of mutable in-place changes. Offering both makes Scala flexible for both functional and imperative (Java-like) code.
Java arrays are inherently mutable—think int[] arr = new int[5]; arr[0] = 42;—this is a fundamental part of the Java platform. Scala’s Array is a thin wrapper around Java arrays, so it retains mutability to ensure seamless interoperability with Java code and libraries.
You’re right that Arrays and List have different use cases:
- Scala
Array(like Java arrays) is optimized for fast random access (O(1) index lookups) and fixed-size (or resizable viaArrayBuffer) operations. - Scala
Listis optimized for fast prepends and functional operations (likemap,filter) where immutability is key.
This split makes perfect sense from a Java perspective: it keeps the familiar mutable array for low-level, performance-critical code, while offering a dedicated immutable list for functional programming. No overlap, just clear division of labor.
At its heart, Scala’s collection library is designed to bridge Java’s imperative, mutable world with functional programming’s immutable, side-effect-free paradigm:
- Default to immutable collections to solve Java’s thread-safety headaches and encourage cleaner functional code.
- Provide mutable alternatives for developers who need Java-like behavior.
- Avoid redundant functionality (hence no mutable List—use
ArrayBufferinstead) to keep the library focused and consistent.
内容的提问来源于stack exchange,提问作者Gibbs

