为什么java.util.ArrayList允许添加null?


41

我不知道为什么java.util.ArrayList允许添加null。在任何情况下我都想添加nullArrayList吗?

我问这个问题是因为在一个项目中,我们有一个错误,其中一些代码正在添加null到,ArrayList并且很难发现该错误在哪里。显然NullPointerException抛出了a ,但是直到其他代码尝试访问该元素时才抛出。问题是如何找到添加null对象的代码。如果ArrayList在要添加元素的代码中引发异常,那会更容易。


12
番石榴项目有一个关于这个问题非常有趣的页面(他们不允许null在他们的大部分收藏)。
约阿希姆·绍尔

6
我相信这里给出的答案很好地覆盖了这个问题。也许应该提到的一件事是:不要把JDK中的所有东西都当作是神圣而完美的,然后and着脑子试图理解为什么它是如此“完美”。有些事情是(诚实的,恕我直言)错误,由于向后兼容而保留在那里。甚至Java创建者也承认这一点,只要阅读Joshua Bloch的书就可以看到他对某些Java API的批评。无论如何,您的问题归结为没有一种更优雅的方法来捕获Java中的NPE。答案是,不,但应该存在。
Shivan Dragon'9

2
您能否提供更多有关为什么不应使用它的信息?如果仅是口味问题,则应选择限制性较小的产品。
无限母马2014年

简单的答案就是null,不管您是否喜欢,它都是表示Java中缺失数据的默认方式。实际上,很多人不喜欢它,并使其成为函数式编程风格的东西的论据。最受支持的答案没有意义/没有抓住问题的实质。
xji

@JIXiang您过于简化了null。“缺少”只是对的几种潜在解释之一null。其他有效的解释可能是“未知”,“不适用”或“未初始化”。null代表什么取决于应用程序。正如Python社区会说的那样:“面对模棱两可,拒绝猜测的诱惑。” 拒绝在完全有能力做到这一点的容器中保留null只是一种猜测。
riwalk

Answers:


34

这个设计决定似乎主要是由命名驱动的。

名称ArrayList向读者建议类似于数组的功能-Java Collections Framework设计人员很自然地希望绝大多数API用户将依赖于它的类似于数组的功能。

这尤其涉及空元素的处理。知道以下情况的API用户可以正常使用:

array[0] = null; // NPE won't happen here

如果发现类似ArrayList的代码是否会抛出NPE,将感到非常惊讶

arrayList.set(0, null); // NPE => WTF?

JCF教程中强调了上述推理,这表明ArrayList与纯数组之间存在相似之处:

ArrayList ...提供了恒定时间的位置访问,并且非常快 ...

如果您希望List实现禁止使用null,最好将其命名为like NonNullableArrayList或类似名称,以避免混淆API用户。


旁注下面的注释中有一个辅助讨论,以及支持此处列出的推理的其他注意事项


12
考虑到LinkedList 支持null列表条目,这种解释并不令人信服。
Stephen C

12
是的,但是更简单,更合理的解释是,null在很多情况下允许输入是有用的。
Stephen C

7
ArrayList之所以这样称呼是因为它模仿一个数组。之所以这样称呼,是因为它是一个实现为数组的列表。就像TreeMap的行为不像树一样。
Florian F

11
IMO,这个答案是完全错误的。允许使用空值,因为在Java中,无论好坏,(IMO,更糟),空值都被用来表示未初始化或丢失的值。它是如何获得最多票数和“接受”检查的?严重的是,这些天我真的对StackOverflow失去了信心。
user949300

8
这个答案是完全错误的。这只是关于列表实现中允许使用null的不受支持的猜测。这里是一个综述 Java集合允许/不允许空的; 请注意,它与数组的相似性无关
Andres F.

32

空值可能是列表元素的有效值。假设您的列表包含一些元素,这些元素代表有关用户列表的一些可选数据,并以与用户相同的顺序存储。如果填充了其他数据,则您的列表将包含其他数据,否则对应于用户的插槽将为空。(我敢肯定有更好的例子,但是你明白了)

如果您不想允许添加null,则可以使用自己的包装器包装数组列表,该包装器在添加null时会抛出。


2
这似乎是一个为什么应该允许空值的错误示例-与在列表中使用空值相比,存在更好的表示可选数据的方法。
casablanca 2012年

@casablanca是的,完全同意,这不是一个很好的例子。
山姆·霍尔德

我找不到ArrayList包含空值的充分理由,否则下一个开发人员“发现”它时就会感到意外:/
AndreasScheinert 2012年

7
@casablanca虽然我同意您的观点,但在Java中,无论是好是坏,都应该避免使用null来表示可选数据,这是“传统的”。
user949300

2
一个可靠的用例:您希望将参数作为列表传递给某个动态函数。您有几个函数,每个函数都有不同的参数集,因此您需要一个动态大小的数组,并且始终可以将null作为有效的函数参数传递!
Falco 2015年

19

ArrayList在设计上允许为null。这是故意的。从javadoc

“ [ArrayList是List接口的可调整大小的数组实现。实现所有可选的列表操作,并允许包括null在内的所有元素。”

“为什么”的答案是,如果没有ArrayList,则在必须将a null放入列表的情况下将不可用。相比之下,可以通过在添加值之前测试值或使用防止这种情况的包装器来防止ArrayList包含空值。

在任何情况下我想向ArrayList添加null吗?

显然,任何情况下null都有明显的含义。例如,这可能意味着列表中给定位置的值尚未初始化或提供。

如果ArrayList在添加元素的代码中引发了异常,那会更容易。

您可以通过创建包装器类轻松实现该行为。但是,这不是大多数程序员/应用程序所需要的行为。


8

在任何情况下我想向ArrayList添加null吗?

当然,预分配呢?您想要一个ArrayList由于信息不足而无法创建的东西。仅仅因为您无法想到某人可能想做某事的原因,这并不意味着一个坏主意。随你。(现在,我敢肯定有人会来,说您应该有空的对象,这些对象可以实现他们在某个晦涩的博客上所读到的某种模式,并且程序员应该真正能够编写程序而无需使用if语句,等等。)

如果你们有一个合同,null容器中永远不应该有s,那么要由您来确保合同是正确的,这很可能是通过断言来进行的。可能最多要花10行代码。Java使您轻松地执行此类操作。JDK无法读懂您的想法。


1
您的preallocation参数无效,因为它已经使用ensureCapacity(int minCapacity)方法和ArrayList(int initialCapacity)构造函数内置在ArrayList中。
菲利普2014年

7
@Philipp它会在那个空间中赋予什么价值?
詹姆斯

显而易见的选择是null在中预先分配(但尚未使用)条目ArrayList;但是我们可以ensureCapacity这样做,但不允许其他功能这样set做。其他地方给出的理由似乎更充分。
大卫·K

@DavidK:说set一个项目应该有可能由返回的任何值都是有道理的get。即使get对已分配空间但从未写入空间的项目进行的正常尝试应该引发异常而不是返回null,但使用一对允许list1.setOrEraseIfNull(index, list2.getOrReturnNull(index))而不是需要的方法还是很有用的if (list2.valueSet(index)) list1.set(index, list2.get(index)); else list1.unset(index);
-supercat

1
@DavidK:尝试读取已分配但尚未写入的条目必须产生null或引发异常;让它返回null更容易。
2014年

4

这似乎是一个(软件)哲学问题。

ArrayList 因为实用程序类的目的是在可能的用例范围内提供帮助。

与您不赞成接受将null作为有效值的隐含主张相反,在许多示例中,NULL值都是完全合法的。

的一个最重要的原因是nulldo not know等同的任何引用类型,包括框架类型。这意味着在任何情况下都不能用更流畅的nothing值替换null 。

因此,可以说您将Integers 1、3、7存储在其数组列表中的相应索引处:由于进行了一些计算,您希望将元素存储在索引5中,因此数组应返回的内容是:“未存储任何值”。这可以通过返回null或NullObject来实现。在大多数情况下,返回内置的null值足够表达。在调用可以返回null 的方法并使用其返回值后,针对返回值检查null是否是现代代码中很常见的事情。


4

该声明

File f = null;

是有效且有用的(我认为不需要解释原因)。拥有文件的集合同样有用,其中一些文件可能为null。

List<File> files = new ArrayList<File>();
// use my collection of files
// ....
// not using this one anymore:
files.set(3, null);

可能包含空对象的集合的有用性直接源自可能为空的对象的有用性。真的就是这么简单。


2

接受一切要比加以限制要容易得多,然后在事实发生之后尝试开放您的设计。

例如,如果他们oracle / sun仅提供NonNullableArrayList,但是您希望能够将Null添加到列表中,该怎么办?你会怎么做?您可能必须创建一个完全不同的对象,无法使用扩展NonNullableArrayList。相反,如果您有一个接受所有内容的ArrayList,则可以轻松地对其进行扩展,并覆盖不接受空值的添加。


2
不同意 一旦功能失调得到广泛使用,就很难纠正太多的问题。如果语言设计师在稍后的阶段允许使用null,则不会破坏现有程序,但事实并非如此。
Andres F.

2
但我同意。这是关于最大化功能。您可以使用一个接受null的列表,即使您不需要它们。如果需要空值,则不能使用拒绝空值的列表。
Florian F

-1

空值的有用性?

因此,当您使用“ 列表列表”来建模具有不同位置的2D现实生活板块时,非常重要。这些位置的一半可能是空的(在随机坐标中),而填充的位置不代表简单的intString而是由复杂的对象代表。如果要保留位置信息,则需要用null填充空白点,以便list.get(x).get(y)不会导致令人讨厌的惊喜。要解决null异常,您可以检查null(非常流行),也可以使用Optional(在这种情况下,我觉得很方便)。另一种方法是用“垃圾”物体填充空白区域,这可能会导致各种混乱。如果您的空检查失败或被遗忘在某个地方,Java会通知您。另一方面,未被正确检查的“垃圾”占位符对象可能会被忽略。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.