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

如何设计一个包含java.lang.String的不可变值类? 客观的,java,guava,immutability,Java,Guava,Immutability,创建一个类,用作对象的不可变列表 方法 我决定利用的集合,而不是用包装一个简单的,因为我知道这样可以避免对后台进行不必要的并发检查,而后台不知道被包装(来源:) 要求 类可以是跨线程使用的“值持有者” 创建后不允许任何代码更改内部值 很高兴拥有 类应该实现,以便按照创建顺序对值进行迭代 一组给定的应该只有一个类 尝试 这里有一些尝试,尽管可能有更多的组合。原谅这个幽默的表演 尝试#1(包括用法示例) import java.util.List; 导入com.google.common.c

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

方法 我决定利用集合,而不是用包装一个简单的,因为我知道这样可以避免对后台进行不必要的并发检查,而后台不知道被包装(来源:)

要求
  • 类可以是跨线程使用的“值持有者”
  • 创建后不允许任何代码更改内部值
很高兴拥有
  • 类应该实现,以便按照创建顺序对值进行迭代
  • 一组给定的应该只有一个类
尝试 这里有一些尝试,尽管可能有更多的组合。原谅这个幽默的表演

尝试#1(包括用法示例)
import java.util.List;
导入com.google.common.collect.ImmutableList;
类BritnetPearsPellings实现了Iterable{
公共静态拼写(字符串…拼写){
BritnetsPearsPellings BritneyPears=新的BritnetsPearsPellings();
britneySpears.spellings=不可变列表.copyOf(拼写);
返回英国梨;
}
私人名单拼写;
英国私人会计师事务所{
}
公共列表getSpellings(){
返回拼写;
}
}
@凌驾
公共迭代器迭代器(){
返回拼写。迭代器();
}
公共类用法{
公共静态void main(字符串[]args){
例如(String sepllin:BritnetSpearsSpellings.of(“布列塔尼·斯皮尔斯”、“布列特尼·斯皮尔斯”、“布列塔尼·斯皮尔斯”))
System.out.printf(“您喜欢这样说:%s%n”,sepllin);
}
}
}
尝试#2
类BritnetSpearsPellings实现了Iterable{
公共静态拼写(字符串…拼写){
BritnetsPearsPellings BritneyPears=新的BritnetsPearsPellings();
britneySpears.spellings=不可变列表.copyOf(拼写);
返回英国梨;
}
私有不可变列表拼写;
英国私人会计师事务所{
}
公共不可变列表getSpellings(){
返回拼写;
}
@凌驾
公共迭代器迭代器(){
返回拼写。迭代器();
}
}
尝试#3
类BritnetSpearsPellings实现了Iterable{
公共静态拼写(字符串…拼写){
BritnetsPearsPellings britneySpears=新的BritnetsPearsPellings(ImmutableList.copyOf(拼写));
返回英国梨;
}
私有最终不可变列表拼写;
私有BritnetSpearsSpellings(不可变列表拼写){
this.spellings=拼写;
}
公共不可变列表getSpellings(){
返回拼写;
}
@凌驾
公共迭代器迭代器(){
返回拼写。迭代器();
}
}
差异摘要
  • 1将保存在公共接口中,在JavaDoc中记录不变性。
  • 2将所有内容存储和公开为
  • 3以创建专门构造函数为代价,将内部引用保持为最终引用,在没有其他初始化选项的情况下,可能会使静态工厂方法初始化看起来很愚蠢(在实际类中实际存在)
问题: 请帮助我从这些实现中选择一个,并说明选择背后的原因

我认为方法#2的主要缺点是,客户需要知道/了解专门的类型,可能他们不应该这样做?

我会使用
尝试#2
而不是
尝试#1
,因为它记录了您总是返回不可变列表实例。通常,选择尽可能具体的返回类型和尽可能一般的参数类型是很有用的。但对于这两种情况,我们更喜欢接口而不是具体的类

嗯,
ImmutableList
是一个抽象类,而不是一个接口。但由于它的性质,它的行为非常像一个接口

当类成员引用
拼写在对象的生命周期内无法更改,并且/或者您希望使整个类本身不可变时,
trunt#3
是有意义的。否则,当
拼写
可以在对象生存期内分配给另一个不可变列表时,它就没有意义了

考虑到您示例中的用例,我倾向于说#3是最佳选择。

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


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

从你的问题陈述(“一组给定的字符串应该只有一个类”),听起来你真正想要的是一个
Interner

  • 是一个实用程序(使用
    Interners.newStrongInterner()
    构造一个),用于确保只有一个对象实例和任何给定数据
  • 正确答案是c吗
    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);
        }
      }
    }
    
    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();
      }
    }
    
    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();
      }
    }