代码之家  ›  专栏  ›  技术社区  ›  James Michael Hare

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

  •  2
  • James Michael Hare  · 技术社区  · 11 年前

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

    现在,自从 Collections.unmodifiableList 犹豫不决 无效的 ,我现在有这个:

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

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

    4 回复  |  直到 11 年前
        1
  •  6
  •   Tom Hawtin - tackline    11 年前

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

        2
  •  3
  •   Stephen C    11 年前

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

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

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

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

    2. 如果你没有意识到 无效的 是表示一个空列表的方法,那么 无效的 是“出乎意料的”,你应该突出让它抛出一个NPE,这样你就可以找到并解决原因。(它可能是一个你认为在其他地方初始化的变量……但不是。这是一个错误。)

    3. 对于您想要的是“只读”列表还是“不可变”列表,存在一些困惑:

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

        3
  •  1
  •   Kevin Day    11 年前

    生成的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)之前,要认真思考。这种行为可以隐藏错误——最好是快速失败并迫使调用方思考他们在做什么。

        4
  •  1
  •   Daniel Pryden    11 年前

    我更喜欢的方式是使用 Guava :

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

    就像tackline的答案一样,这也抛出了一个异常,而不是无声地将null转换为空列表。

    与这里的其他答案不同,使用 ImmutableList.copyOf() 确保调用者不能向您传递一个列表,以便稍后进行变异。