如何处理方法返回的空值?
How to handle a null returned from a method?
我有一个图相关的方法returns某个节点的相邻节点。
如果一个节点没有邻居它returns null,方法如下
public Iterable<Node> getNeighbors(Node v) {
if (!this.adjacencyList.get(v).isEmpty())
return this.adjacencyList.get(v);
return null;
}
我尝试使用以下方法避免异常:
if (graph.getNeighbors(nodeIterator.name) == null)
nodeIterator = all_graph_nodes.iterator().next();
Iterable<Node> adjNodes = graph.getNeighbors(nodeIterator.name);
NullPointerException
即使使用前面的代码也会引发。
如何解决这个问题?
您应该避免从 getNeighbors 方法中 returning null。对于 Iterables、Iterators 和 Collections,return null 不是好的做法,因为一个空的 iterable 将表示相同的概念(该邻接列表中没有任何内容)而没有 null 的所有危险。而且您的代码会更简单。您可以检查可迭代对象是否包含任何内容,如果不包含则默认为完整迭代器。
如果您仍然收到 NPE,那么问题出在 getNeighbours
而不是第二个代码段。
this.adjacencyList
为空,-OR-
this.adjacencyList.get(v)
returns null.
假设您将 name 传递给一个方法,然后该方法将通过 node 进行查找,并且您可以'不要在列表上调用 .get(someNodeRef)
,adjacencyList
可能是某种哈希图,所以你的名字不对,你应该重命名一些东西。 Map 的 .get(x)
方法 returns null
如果找不到条目,那么罪魁祸首很可能是 v
根本不在地图中,因此 .get(v).isEmpty()
抛出 NPE。
修正如下:
当携带预期语义的有效标记值可用时,您应该 NEVER return null。有点啰嗦,但它的意思是:当您打算以与 'zero nodes' 完全相同的方式对待它时,为什么要 returning null?有一个 Iterable<Node>
的实例正确地表示了零节点的概念,但它不是 null
。它是 List.of()
或等价物:空列表没有节点。伟大的。这就是你的意图。所以 return 那。
.get(v).isEmpty()
在这里是错误的代码,因为这意味着如果您请求一个不存在的节点,就会发生 NPE。当然,除非您希望 它以这种方式工作。一个简单的出路是默认机制:改为调用 .getOrDefault
:
if (!this.adjacencyList.getOrDefault(v, List.of()).isEmpty()) ....
除了,当然,当你可以 return 一个空列表时,你永远不应该 returning null,所以你的 getNeighbours 方法变得简单:
return adjacencyMap.getOrDefault(v, List.of());
一条线就能解决所有问题。
一般来说,如果您正在编写以某种方式处理 null
的代码,并且以相同的方式处理一些标记值(例如空白字符串或空列表),那么您的代码风格很糟糕;但是你得到 null
应该得到那个空值。例如如果你写过这个:
if (x == null || x.isEmpty()) ...
你搞砸了。弄清楚你从哪里得到 x 的。在那里更新它,使 x 成为空白标记(""
用于字符串,List.of
用于列表,等等)。
那个,并更多地使用 .getOrDefault
和其他类似的方法:让您提供在以下情况下应该发生什么的方法。找不到密钥。
您应该不惜一切代价避免 returning null
。这是非常危险的,因为它可能会导致在运行时抛出空指针异常。此类异常很难调试,因为它们通常会隐藏实现错误,因为抛出异常的位置很可能远离原始实现错误。
您的案例实际上是此类行为的一个很好的例子,因为无法直接理解 NPE 的来源。
在 null
值的出现是不可避免的情况下(例如,正如@rzwitserloot 指出的那样,Java 的 Map get
method) and there is the possibility of exposing it to client objects (e.g. your getNeighbors
method may expose such null
value) I like to use Java's Optional (如文档中所述)是:
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
此对象将充当可分配为 null
的对象的包装器,从而防止直接使用它并且 可能 防止抛出 NPE。
在你的情况下,这将按如下方式应用(请注意,这是假设 adjancencyList
是一个非空对象并且它的 get
方法是实际抛出 NPE 的方法):
public Optional<Iterable<Node>> getNeighbors(Node v) {
return Optional.ofNullable(this.adjacencyList.get(v));
}
if (!graph.getNeighbors(nodeIterator.name).isPresent()) {
nodeIterator = all_graph_nodes.iterator().next();
}
Iterable<Node> adjNodes = graph.getNeighbors(nodeIterator.name).get();
请注意,通过将原始 get
方法包装在 Optional
对象中,将不再传播原始 null
值,从而阻止客户端使用它。您只是将处理 null
的责任转移到您这边,并保护客户来处理它们。
使用 Optional
作为方法的 return 类型的另一个巨大优势是它隐式声明了方法的 return 对象可能存在也可能不存在。这迫使客户了解其 return 值可能为空 (null
),从而迫使其采取相应行动。
我有一个图相关的方法returns某个节点的相邻节点。 如果一个节点没有邻居它returns null,方法如下
public Iterable<Node> getNeighbors(Node v) {
if (!this.adjacencyList.get(v).isEmpty())
return this.adjacencyList.get(v);
return null;
}
我尝试使用以下方法避免异常:
if (graph.getNeighbors(nodeIterator.name) == null)
nodeIterator = all_graph_nodes.iterator().next();
Iterable<Node> adjNodes = graph.getNeighbors(nodeIterator.name);
NullPointerException
即使使用前面的代码也会引发。
如何解决这个问题?
您应该避免从 getNeighbors 方法中 returning null。对于 Iterables、Iterators 和 Collections,return null 不是好的做法,因为一个空的 iterable 将表示相同的概念(该邻接列表中没有任何内容)而没有 null 的所有危险。而且您的代码会更简单。您可以检查可迭代对象是否包含任何内容,如果不包含则默认为完整迭代器。
如果您仍然收到 NPE,那么问题出在 getNeighbours
而不是第二个代码段。
this.adjacencyList
为空,-OR-this.adjacencyList.get(v)
returns null.
假设您将 name 传递给一个方法,然后该方法将通过 node 进行查找,并且您可以'不要在列表上调用 .get(someNodeRef)
,adjacencyList
可能是某种哈希图,所以你的名字不对,你应该重命名一些东西。 Map 的 .get(x)
方法 returns null
如果找不到条目,那么罪魁祸首很可能是 v
根本不在地图中,因此 .get(v).isEmpty()
抛出 NPE。
修正如下:
当携带预期语义的有效标记值可用时,您应该 NEVER return null。有点啰嗦,但它的意思是:当您打算以与 'zero nodes' 完全相同的方式对待它时,为什么要 returning null?有一个
Iterable<Node>
的实例正确地表示了零节点的概念,但它不是null
。它是List.of()
或等价物:空列表没有节点。伟大的。这就是你的意图。所以 return 那。.get(v).isEmpty()
在这里是错误的代码,因为这意味着如果您请求一个不存在的节点,就会发生 NPE。当然,除非您希望 它以这种方式工作。一个简单的出路是默认机制:改为调用.getOrDefault
:
if (!this.adjacencyList.getOrDefault(v, List.of()).isEmpty()) ....
除了,当然,当你可以 return 一个空列表时,你永远不应该 returning null,所以你的 getNeighbours 方法变得简单:
return adjacencyMap.getOrDefault(v, List.of());
一条线就能解决所有问题。
一般来说,如果您正在编写以某种方式处理 null
的代码,并且以相同的方式处理一些标记值(例如空白字符串或空列表),那么您的代码风格很糟糕;但是你得到 null
应该得到那个空值。例如如果你写过这个:
if (x == null || x.isEmpty()) ...
你搞砸了。弄清楚你从哪里得到 x 的。在那里更新它,使 x 成为空白标记(""
用于字符串,List.of
用于列表,等等)。
那个,并更多地使用 .getOrDefault
和其他类似的方法:让您提供在以下情况下应该发生什么的方法。找不到密钥。
您应该不惜一切代价避免 returning null
。这是非常危险的,因为它可能会导致在运行时抛出空指针异常。此类异常很难调试,因为它们通常会隐藏实现错误,因为抛出异常的位置很可能远离原始实现错误。
您的案例实际上是此类行为的一个很好的例子,因为无法直接理解 NPE 的来源。
在 null
值的出现是不可避免的情况下(例如,正如@rzwitserloot 指出的那样,Java 的 Map get
method) and there is the possibility of exposing it to client objects (e.g. your getNeighbors
method may expose such null
value) I like to use Java's Optional (如文档中所述)是:
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
此对象将充当可分配为 null
的对象的包装器,从而防止直接使用它并且 可能 防止抛出 NPE。
在你的情况下,这将按如下方式应用(请注意,这是假设 adjancencyList
是一个非空对象并且它的 get
方法是实际抛出 NPE 的方法):
public Optional<Iterable<Node>> getNeighbors(Node v) {
return Optional.ofNullable(this.adjacencyList.get(v));
}
if (!graph.getNeighbors(nodeIterator.name).isPresent()) {
nodeIterator = all_graph_nodes.iterator().next();
}
Iterable<Node> adjNodes = graph.getNeighbors(nodeIterator.name).get();
请注意,通过将原始 get
方法包装在 Optional
对象中,将不再传播原始 null
值,从而阻止客户端使用它。您只是将处理 null
的责任转移到您这边,并保护客户来处理它们。
使用 Optional
作为方法的 return 类型的另一个巨大优势是它隐式声明了方法的 return 对象可能存在也可能不存在。这迫使客户了解其 return 值可能为空 (null
),从而迫使其采取相应行动。