三元运算符在条件未满足的情况下评估条件语句

3

我写了一些代码,这里是相关片段:

@NonNullByDefault
public class Score<NUMERAL, LITERAL>
{
    protected NUMERAL value;
    @Nullable
    protected LITERAL literal;
    [...]

我已经重写了equals()方法,如下所示:

@Override
public boolean equals(@Nullable Object object)
{
    if(object == null) return false;
    if(object == this) return true;

    if( object instanceof Score)
    {
        return ((Score<NUMERAL, LITERAL>) object).getValue().equals(value) &&
                literal == null ? ((Score<NUMERAL, LITERAL>) object).getLiteral() == null : literal.equals(((Score<NUMERAL, LITERAL>) object).getLiteral());
    }
    return false;
}

基本上,这个想法是一个分数(Score)只能有一个数字值,此时字面量(literal)为空。我已经编写了一些单元测试,并在下面的代码中遇到了空指针异常:
[....]
Score<Float, String> score = new Score<>(0.0f);
Score<Float, String> anotherScore = new Score<>(1.0f, "One");
[....]

assertFalse(score.equals(anotherScore));

如果我没有理解错的话,在equals中使用短路操作符不应该会阻止后面的任何表达式被执行,因为第一个表达式已经是false了吗?此外,为什么会有异常?由于条件为真,我希望三元表达式的表达式被评估,而条件表达式被跳过。根据我在规范中读到的内容,这应该是行为。此外,我在这里发现了一个问题:Java ternary (immediate if) evaluation 这应该对我的思维过程有所帮助。

也许我忽略了一些非常明显的东西,但我已经没有想法了。也许你可以帮忙解决?

1个回答

3

它确实会短路,但不是你想要的方式。&&的优先级高于三目运算符?: - 因此,这样做(为了澄清而添加缩进、换行和注释)

((Score<NUMERAL, LITERAL>) object).getValue().equals(value) &&
literal == null
    ? ((Score<NUMERAL, LITERAL>) object).getLiteral() == null
    : literal.equals(((Score<NUMERAL, LITERAL>) object).getLiteral())

实际上意味着这个:

//the first line as a whole is the condition for ?:
((Score<NUMERAL, LITERAL>) object).getValue().equals(value) && literal == null
    ? ((Score<NUMERAL, LITERAL>) object).getLiteral() == null
    : literal.equals(((Score<NUMERAL, LITERAL>) object).getLiteral())

这意味着实际上,如果条件的第一部分为falseliteralnull,则您将自动进入表达式的:部分,在该部分中调用literal.equals,从而导致NullPointerException

修复很简单:添加括号告诉Java你想让什么东西被评估:

((Score<NUMERAL, LITERAL>) object).getValue().equals(value) && 
(literal == null 
    ? ((Score<NUMERAL, LITERAL>) object).getLiteral() == null
    : literal.equals(((Score<NUMERAL, LITERAL>) object).getLiteral()))

@durron597,OP似乎是一个能够自己解决问题的程序员,但我想这样做也无妨。立即包含它。 - kviiri
1
我同意,但是未来的读者可能会遇到这个问题,但可能不那么聪明 :). 不管怎样,在评论之前,我+1了; 感谢你做出编辑。 - durron597
非常感谢,我会在周一第一时间进行测试。简直不敢相信我犯了这么明显的错误!至少我又学到了一个宝贵的教训!;) - Eric Tobias
@EricTobias,没问题。我也得为这个答案检查一下优先级顺序! - kviiri
运行得很好,干杯! - Eric Tobias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接