构建只读空列表的最佳方法是什么?

时间:2013-02-20 03:09:16

标签: java java-6

我正在我的系统中创建一个“事件”的不可变表示,因此对于在构造函数中传递的所有者列表,我想对它们进行只读视图。此外,如果他们传入null列表,我想在这种情况下制作一个只读的空列表。

现在,自从Collections.unmodifiableList null以来,我现在有了这个:

userOwners_ = Collections.unmodifiableList(userOwners != null 
                                           ? userOwners 
                                           : new ArrayList<String>(0));

但这似乎有点丑陋和低效。在Java中有更优雅的方法吗?

4 个答案:

答案 0 :(得分:5)

Collections.emptyList()。但严重的是,null应该是NPE。

答案 1 :(得分:3)

同样丑陋,但效率稍高的答案

userOwners_ = userOwners != null ? 
                  Collections.unmodifiableList(userOwners) :
                  Collections.emptyList();

然而,还有其他一些事情要注意。

  1. 似乎在某些时候,有人决定使用null来表示空列表。这是糟糕的设计......导致需要特殊处理。最好将其设置为新列表,如果您知道列表始终为空,则为emptyList()

  2. 如果你没有有意识地决定null是表示空列表的方式,那么null是“意外的”,你应该让它抛出一个NPE,所以你可以追踪并解决原因。 (它可能是你假设的变量在其他地方被初始化......但不是。这是一个错误。)

  3. 对于您是否需要“只读”列表或“不可变”列表存在一些疑惑:

    • unmodifiableList()方法为您提供了一个无法修改的列表;即它是“只读”。但原始列表仍然可以修改,这些更改将通过“只读”包装器显示。
    • 如果您想要一个“不可变”列表(即根本无法更改的列表),您需要clone()原始列表,然后使用unmodifiableList()包装克隆。
    • 这些都不会使列表中的元素(“所有者”对象)成为不可变的(如果它们不是不可变的)。
  4. 标识符userOwners_是最广泛接受/使用的Java样式指南中的代码样式违规。

答案 2 :(得分:1)

结果userOwners_仍然是可变的 - 对userOwners的任何更改都将成为userOwners _的一部分。

如果您真的希望该成员变量是不可变的,那么正确的方法是这样做:

private final List<String> userOwners;

public MyObject(List<String> userOwners){
  this.userOwners = userOwners != null ? Collections.unmodifiableList(new ArrayList<String>(userOwners)) : Collections.emptyList();
}

作为一个小问题,您的成员变量命名不符合Java样式指南(userOwners_对我们这些经常阅读Java代码的人来说很奇怪)

扩展另一张海报所写的内容:在接受公共方法的空输入(不抛弃NPE)之前,真的很难想。这种行为可以隐藏错误 - 更好地快速失败并迫使调用者思考他们正在做什么。

答案 3 :(得分:1)

我首选的方法是使用Guava

this.userOwners = ImmutableList.copyOf(Preconditions.checkNotNull(userOwners));

与tackline的答案一样,这也会引发异常,而不是将null静态转换为空列表。

与此处的其他答案不同,使用ImmutableList.copyOf()可确保调用者无法向您传递他们以后可以变异的列表。