Prompts-MCP 686 skills · ai / design / design-pattern / framework / fundamentals / habit / lang / tech-selection /mcp/sse
lang lang/java/collections/immutable-collections.md medium

java-immutable-collections

暴露只读集合 — List.of/Map.of、Collections.unmodifiableList、防御性拷贝,以及 Arrays.asList 的固定长度坑。Use when 返回内部集合给外部 / 定义常量集合 / 接收外部传入集合做字段时。

不可变集合immutable collectionlist.of map.ofunmodifiablelist防御性拷贝defensive copyarrays.aslist
paths
  • *.java

Java · 不可变与只读集合

本条只管「怎么不让集合被外部改坏」。选哪个实现见 collection-choice.md;并发安全见 concurrent-collections.md

规则

场景
定义常量集合 / 真不可变集合 List.of(...) / Map.of(...) / Set.of(...)(Java 9+)
把可变集合包成只读视图返回 Collections.unmodifiableList(...)
getter 返回内部集合 / 构造器接收外部集合存为字段 防御性拷贝new ArrayList<>(src)

unmodifiableList视图:底层原集合改了视图跟着变,所以包之前通常要先拷贝。

正例

// ✅ 常量集合用 List.of,本身不可变、不含 null
private static final List<String> ROLES = List.of("ADMIN", "USER");

// ✅ getter 防御性拷贝,外部拿到的改动不影响内部
public List<Order> getOrders() {
    return new ArrayList<>(this.orders);
}

// ✅ 构造器接收外部集合也要拷贝,切断外部引用
public Cart(List<Item> items) {
    this.items = new ArrayList<>(items);
}

反例

// ❌ Arrays.asList 返回定长视图:add/remove 抛 UnsupportedOperationException,
//    且改数组会串改 list
List<Integer> nums = Arrays.asList(1, 2, 3);
nums.add(4);  // UnsupportedOperationException

// ❌ 直接返回内部集合:外部可随意 add/remove,破坏封装
public List<Order> getOrders() {
    return this.orders;
}

理由:Arrays.asList 既不是真不可变也不是普通 ArrayList,是个长度固定的桥接视图;直接返回内部集合等于把私有状态交给外部修改。List.of 返回的集合既不可变也禁止 null 元素。

自检

  • [ ] 常量集合用 List.of / Map.of / Set.of,没用 Arrays.asList 凑数?
  • [ ] getter 返回内部集合时做了防御性拷贝(或包 unmodifiableXxx)?
  • [ ] 构造器/setter 接收外部集合时拷贝了,没直接存引用?
  • [ ] 清楚 unmodifiableList 是视图、底层变它也变?

相关