关于java:Java中的不可变集合我们换个方式理解

49次阅读

共计 2449 个字符,预计需要花费 7 分钟才能阅读完成。

不可变汇合例:

public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
        "red",
        "orange",
        "yellow",
        "green",
        "blue",
        "purple");

class Foo {
    Set<Bar> bars;
    Foo(Set<Bar> bars) {this.bars = ImmutableSet.copyOf(bars); // defensive copy!
    }
}

为什么要应用不可变汇合

不可变对象有很多长处,包含:

  • 当对象被不可信的库调用时,不可变模式是平安的;
  • 不可变对象被多个线程调用时,不存在竞态条件问题
  • 不可变汇合不须要思考变动,因而能够节省时间和空间。所有不可变的汇合都比它们的可变模式有更好的内存利用率(剖析和测试细节);
  • 不可变对象因为有固定不变,能够作为常量来平安应用。

创建对象的不可变拷贝是一项很好的防御性编程技巧。Guava 为所有 JDK 规范汇合类型和 Guava 新汇合类型都提供了简略易用的不可变版本。
JDK 也提供了 Collections.unmodifiableXXX 办法把汇合包装为不可变模式,但咱们认为不够好:

  • 轻便而且累赘:不能舒服地用在所有想做防御性拷贝的场景;
  • 不平安:要保障没人通过原汇合的援用进行批改,返回的汇合才是事实上不可变的;
  • 低效:包装过的汇合依然保有可变汇合的开销,比方并发批改的查看、散列表的额定空间,等等。

如果你没有批改某个汇合的需要,或者心愿某个汇合放弃不变时,把它防御性地拷贝到不可变汇合是个很好的实际。

重要提醒:所有 Guava 不可变汇合的实现都不承受 null 值。咱们对 Google 外部的代码库做过具体钻研,发现只有 5% 的状况须要在汇合中容许 null 元素,剩下的 95% 场景都是遇到 null 值就疾速失败。如果你须要在不可变汇合中应用 null,请应用 JDK 中的 Collections.unmodifiableXXX 办法。更多细节倡议请参考“应用和防止 null”。

怎么应用不可变汇合

不可变汇合能够用如下多种形式创立:

  • copyOf 办法,如 ImmutableSet.copyOf(set);
  • of 办法,如 ImmutableSet.of(“a”,“b”,“c”) 或 ImmutableMap.of(“a”, 1,“b”, 2);
  • Builder 工具,如
public static final ImmutableSet<Color> GOOGLE_COLORS =
        ImmutableSet.<Color>builder()
            .addAll(WEBSAFE_COLORS)
            .add(new Color(0, 191, 255))
            .build();

此外,对有序不可变汇合来说,排序是在结构汇合的时候实现的,如:

ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");

会在结构时就把元素排序为 a, b, c, d。

比设想中更智能的 copyOf

请留神,ImmutableXXX.copyOf 办法会尝试在平安的时候防止做拷贝——理论的实现细节不详,但通常来说是很智能的,比方:

ImmutableSet<String> foobar = ImmutableSet.of("foo", "bar", "baz");
thingamajig(foobar);

void thingamajig(Collection<String> collection) {ImmutableList<String> defensiveCopy = ImmutableList.copyOf(collection);
    ...
}

在这段代码中,ImmutableList.copyOf(foobar) 会智能地间接返回 foobar.asList(), 它是一个 ImmutableSet 的常量工夫复杂度的 List 视图。
作为一种摸索,ImmutableXXX.copyOf(ImmutableCollection) 会试图对如下状况防止线性工夫拷贝:

  • 在常量工夫内应用底层数据结构是可能的——例如,ImmutableSet.copyOf(ImmutableList) 就不能在常量工夫内实现。
  • 不会造成内存泄露——例如,你有个很大的不可变汇合 ImmutableList<String>

hugeList,ImmutableList.copyOf(hugeList.subList(0, 10)) 就会显式地拷贝,免得不必要地持有 hugeList 的援用。

  • 不扭转语义——所以 ImmutableSet.copyOf(myImmutableSortedSet) 会显式地拷贝,因为和基于比拟器的 ImmutableSortedSet 相比,ImmutableSet 对 hashCode() 和 equals 有不同语义。

在可能的状况下防止线性拷贝,能够最大限度地缩小防御性编程格调所带来的性能开销。

asList 视图

所有不可变汇合都有一个 asList() 办法提供 ImmutableList 视图,来帮忙你用列表模式不便地读取汇合元素。例如,你能够应用 sortedSet.asList().get(k) 从 ImmutableSortedSet 中读取第 k 个最小元素。

asList() 返回的 ImmutableList 通常是——并不总是——开销稳固的视图实现,而不是简略地把元素拷贝进 List。也就是说,asList 返回的列表视图通常比个别的列表均匀性能更好,比方,在底层汇合反对的状况下,它总是应用高效的 contains 办法。

最初

私信回复 材料 支付一线大厂 Java 面试题总结 + 阿里巴巴泰山手册 + 各知识点学习思维导 + 一份 300 页 pdf 文档的 Java 外围知识点总结!

这些材料的内容都是面试时面试官必问的知识点,篇章包含了很多知识点,其中包含了有基础知识、Java 汇合、JVM、多线程并发、spring 原理、微服务、Netty 与 RPC、Kafka、日记、设计模式、Java 算法、数据库、Zookeeper、分布式缓存、数据结构等等。

正文完
 0