我最近得到了一次NPE,当时我绝对确定这是不可能的.这个类是在一个非常多线程的程序中使用的,所以我知道您应该认为基本上任何事情都是可能的,但仍然.
因此,该类定义了以下字段:
private final Set<TcpIpConnection> _connections = new LinkedHashSet<>();
在整个班级中,这个集合只在两个地方被操纵:
// some method
TcpIpConnection tcpipConnection = new ServerConnection(clientSocket, _channels, MyClass.this);
_connections.add(tcpipConnection);
// some other method
_connections.remove(connection);
所以我想你会同意,null
是不可能加到这一组的.是的,布景留在班级里,永远不会扩散到外面.
但现在我有一个测试用例,它有时会失败,并在以下语句中使用NPE,这是类中唯一使用_connections
的另一条语句:
new ArrayList<>(_connections).stream().forEach(c -> c.close("Server down"));
正如您所看到的,我已经通过首先创建集合的本地副本AS ArrayList
来防止ConcurrentModificationException
.
现在NPE显示为c
,这一定是之前添加到_connections
上的值-但它怎么会变成null
呢?
需要明确的是,我并不是在寻找解决方案--我在流中添加了filter(Objects::nonNull)
(或者我在初始化器中使用了Collections.synchronizedSet()
),现在它肯定可以工作了.
这怎么可能发生呢?是的,多线程访问几乎会把一切都搞砸,但把null
放在一个不存在的集合中呢?