在 Java 的三元运算符中,即使表达式结果为假值,也可以计算第一个参数吗?
我最近通过随机临时测试在我的代码中发现了一个不寻常的错误。所以,我为它做了一个测试用例。
这是我的测试用例:
SampleRequest request = new SampleRequest();
request.setA(null);
request.setB(null);
assertEquals(null, request.getAOrB());
A 和 B 被定义为 java.lang.Integer 类型,并具有直接的 setter 方法来将它们的值设置到请求中。
这里还涉及到一个枚举。它有一个原始整数值以及此代码中使用的方法。我将在这里发布相关部分:
enum Swapper {
public int c;
Swapper findSwapperToUse(final int a) {
for(Swapper swapper : values()) {
if(swapper.c == a) {
return swapper;
}
}
return null;
}
}
现在,这是令人困惑的方法。对该方法调用测试方法会导致 NPE,但在该方法的最后一行。
public class SampleRequest {
private Integer A;
private Integer B;
public void setA(final Integer A) {
this.A = A;
}
public void setB(final Integer B) {
this.B = B;
}
public Integer getAOrB() {
return A != null ? Swapper.findSwapperToUse(A).c
: B;
}
}
在测试中,A和B都设置为null。因此,A != null 返回 false。但是,我在 : B 行的行号处收到 NullPointerException。
我的猜测是,由于某种原因,正在评估第一个表达式 Swapper.findSwaperToUse(A).c,因此通过自动装箱调用 A.intValue(),从而导致 null 值出现 NullPointerException。通过调试发现findSwaperToUse()没有被调用。
然而,根据这个问题,这不应该发生: Java 三元(立即 if)评估
未选择的操作数表达式不会针对条件表达式的特定计算进行计算。
返回 null (B) 不会导致 NullPointerException - 在这里返回 null 结果是完全可以的。
到底是怎么回事?
编辑:我忘记补充一点,我通过使用直接的 if 语句更改了代码以避免这种情况 - 以下代码确实按预期工作:
public Integer getAOrB() {
if(A != null) {
return Swapper.findSwapperToUse(A).c;
}
return B;
}
I found an unusual bug in my code recently through random ad-hoc testing. So, I made a test case for it.
Here is my test case:
SampleRequest request = new SampleRequest();
request.setA(null);
request.setB(null);
assertEquals(null, request.getAOrB());
A and B are defined as java.lang.Integer types and have direct setter methods to set their values into the request.
There is also an enumeration involved. It has a primitive integer value, and a method that's used in this code. I'll post the relevant portions here:
enum Swapper {
public int c;
Swapper findSwapperToUse(final int a) {
for(Swapper swapper : values()) {
if(swapper.c == a) {
return swapper;
}
}
return null;
}
}
Now, here's the method that is being confusing. Invoking the test method on that method results in a NPE, but on the last line of the method.
public class SampleRequest {
private Integer A;
private Integer B;
public void setA(final Integer A) {
this.A = A;
}
public void setB(final Integer B) {
this.B = B;
}
public Integer getAOrB() {
return A != null ? Swapper.findSwapperToUse(A).c
: B;
}
}
In the test, both A and B are set to null. Therefore, A != null returns false. However, I get a NullPointerException at the line number for the : B line.
My guess is that for some reason the first expression, Swapper.findSwapperToUse(A).c, is being evaluated, and therefore the A.intValue() is invoked via autoboxing, resulting in a NullPointerException on the null value. Through debugging, it's known that findSwapperToUse() is not invoked.
However, according to this questionthis should not happen:
Java ternary (immediate if) evaluation
The operand expression not chosen is not evaluated for that particular evaluation of the conditional expression.
Returning a null (B) will not result in a NullPointerException - it's perfectly fine to return a null result here.
What the heck is going on?
EDIT: I forgot to add that I altered the code to avoid this by using a straight up if statement - the following code does work as expected:
public Integer getAOrB() {
if(A != null) {
return Swapper.findSwapperToUse(A).c;
}
return B;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我猜问题是由于编译器
从
Swapper.c
的类型推断出整个表达式的类型为int
,因此尝试将拆箱转换应用于B
。以下是 JLS,§15.25 的相关摘录:
您可以通过添加以下强制转换来防止它:
I guess the problem is caused by the fact that compiler infers the type of the whole expression
as
int
from the type ofSwapper.c
, and therefore tries to apply unboxing conversion toB
.Here is the related excerpt from the JLS, §15.25:
You can prevent it by adding the following cast:
您的
findSwaperToUse
方法返回 null,并且您无法执行null.c
。为了确保这一点,我会将您的代码更改为:
Your
findSwapperToUse
method is returning null, and you can't donull.c
.To make sure of this, I would change your code to read: