2

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

现在,由于Collections.unmodifiableList犹豫不决null,我目前有这个:

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

但这似乎有点丑陋和低效。在 Java 中有没有更优雅的方法来做到这一点?

4

4 回答 4

6

Collections.emptyList(). 但说真的,null应该是NPE。

于 2013-02-20T03:19:50.767 回答
3

一个同样丑陋但效率略高的答案是

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

然而,还有一些其他的事情需要观察。

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

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

  3. 关于您想要“只读”列表还是“不可变”列表存在一些混淆:

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

于 2013-02-20T03:20:11.983 回答
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 样式指南(对于我们这些定期阅读 Java 代码的人来说,userOwners_ 很奇怪)

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

于 2013-02-20T03:16:57.987 回答
1

我的首选方式是使用Guava

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

就像 tackline 的回答一样,这也会引发异常,而不是默默地将 null 转换为空列表。

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

于 2013-02-20T03:23:16.250 回答