如何设计一个包含java.lang.String的不可变值类?

Rob*_*ino 8 java immutability guava

目的

创建一个类,用作String对象的不可变列表.

途径

我决定利用Google Guava的ImmutableList <E>集合,而不是用Collections.unmodifiableList(List <?extends T> list)包装一个简单的List <E>,因为我理解这可以避免对后备List <E进行不必要的并发检查>,它不知道被包装(来源:ImmutableCollectionsExplained).

要求

  • 具有跨线程使用的"值持有者"的类
  • 创建后,不允许任何代码更改内部值

尼斯对富人

  • 该类应该按照创建顺序对值进行迭代以实现Iterable <E>
  • 对于给定的String集合,应该只有一个类.

尝试

这里有一些尝试,尽管可能有更多的组合.原谅幽默的演绎.

尝试#1(包括用法示例)

import java.util.List;
import com.google.common.collect.ImmutableList;
class BritnetSpearsSpellings implements Iterable<String> {
  public static BritnetSpearsSpellings of(String... spellings) {
    BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings();
    britneySpears.spellings = ImmutableList.copyOf(spellings);
    return britneySpears;
  }
  private List<String> spellings;
  private BritnetSpearsSpellings() {
  }
  public List<String> getSpellings() {
    return spellings;
  }
}
@Override
public Iterator<String> iterator() {
  return spellings.iterator();
}
public class Usage {
  public static void main(String[] args) {
    for (String sepllin : BritnetSpearsSpellings.of("Brittany Spears", "Brittney Spears", "Britany Spears"))
      System.out.printf("You spel Britni like so: %s%n", sepllin);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

尝试#2

class BritnetSpearsSpellings implements Iterable<String> {
  public static BritnetSpearsSpellings of(String... spellings) {
    BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings();
    britneySpears.spellings = ImmutableList.copyOf(spellings);
    return britneySpears;
  }
  private ImmutableList<String> spellings;
  private BritnetSpearsSpellings() {
  }
  public ImmutableList<String> getSpellings() {
    return spellings;
  }
  @Override
  public Iterator<String> iterator() {
    return spellings.iterator();
  }
}
Run Code Online (Sandbox Code Playgroud)

尝试#3

class BritnetSpearsSpellings implements Iterable<String> {
  public static BritnetSpearsSpellings of(String... spellings) {
    BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings(ImmutableList.copyOf(spellings));
    return britneySpears;
  }
  private final ImmutableList<String> spellings;
  private BritnetSpearsSpellings(ImmutableList<String> spellings) {
    this.spellings = spellings;
  }
  public ImmutableList<String> getSpellings() {
    return spellings;
  }
  @Override
  public Iterator<String> iterator() {
    return spellings.iterator();
  }
}
Run Code Online (Sandbox Code Playgroud)

差异摘要

  • 1将List <E>保留在公共接口中,记录JavaDoc中的不变性.

  • 2存储并公开所有内容,如Google Guava的ImmutableList <E>

  • 3保持内部参考作为最终创造一个专门的构造函数,可能使静态工厂方法初始化的代价看傻在没有其他初始化选项(这实际上是没有在现实类)

题

请帮助我选择其中一个实现,并根据您的选择进行推理.

我认为方法#2的主要缺点是客户需要具有专门的Google Guava类型的认知/可见性,可能他们不应该?

Fra*_*eau 3

显然,我认为#3 是最佳选择。final强制并记录类(的字段)的不可变性,而不仅仅是类本身不可变的事实List。

无论您在 getter 中公开List一些 javadoc 还是实际的 a是另一回事。ImmutableList我见过一些意见,ImmutableList明确地返回文档的意图,但是,您仍然将自己绑定到实现而不是接口,以实现低级别且将来可能需要更改的东西(即使不变性“通常”)好的)。因此,它更像是您的应用程序的一种全局设计选择,而不仅仅是一个用例。如果您确实使用ImmutableList,我认为这对客户端来说不是一个真正的问题,名称是明确的,并且可以通过您的 IDE 轻松看出它是 的实现List,并且如果他们想要更多信息,他们可以访问 javadoc。谁知道呢,他们可能会喜欢它并开始使用它,以及 Guava 提供的所有其他好处:-)