Java-if-else和三元运算符之间的不同行为



最近我发现if-else和三元运算符之间有一个奇怪的行为差异。

我将在下面使用单元测试代码来说明差异。

public class SomeTest {
@Test
void testWithTernary_resultIsLong() {
final SomeClass someClass = new SomeClass();
assertTrue(someClass.getNumberWithTernary() instanceof Long);
assertFalse(someClass.getNumberWithTernary() instanceof Integer);
}
@Test
void testWithIfElse_resultIsInteger() {
final SomeClass someClass = new SomeClass();
assertTrue(someClass.getNumberWithIfElse() instanceof Integer);
assertFalse(someClass.getNumberWithIfElse() instanceof Long);
}
private static class SomeClass {
public Object getNumberWithTernary() {
final long l = this.getLong();
return (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE) ? Math.toIntExact(l) : l;
}
private long getLong() {
return 10L;
}
public Object getNumberWithIfElse() {
final long l = this.getLong();
if (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE) {
return Math.toIntExact(l);
} else {
return l;
}
}
}
}

以上两项测试都成功了。

根据我在工作中遇到的代码,上面声明的类被过度简化了。

主要方法是返回一个Object,该方法需要尽可能返回一个整数(即在整数范围内(,以便在上游更容易消耗。

我最初使用三元运算方法,从未想过它会出乎意料地起作用,直到进行烟雾测试。

有人能解释为什么if-else和三元算子在这种情况下的行为不同吗?

让我们分析一下您的三元表达式(...) ? Math.toIntExact(l) : l

条件并不重要。第二个操作数("then"部分(的类型为int。第三个运算符("其他"部分(属于long类型。

您可以阅读Java语言规范15.25。条件运算符?:以获取精确的规则。但基本上所有的数字操作数都被强制转换为"最宽"类型,因为表达式结果必须只有一个类型,不能返回"longint",Java类型系统不够强大(有些语言实际上可以做到这一点(。

所以编译器基本上将该表达式重写为以下表达式:

(...) ? ((long) Math.toIntExact(l)) : l

为了将long转换为Object,编译器插入自动装箱调用:

Long.valueOf((...) ? ((long) Math.toIntExact(l)) : l)

所以这就是为什么你会看到这种行为的粗略解释。

普通的if语句不能返回值,所以它只返回您在return语句中指定的任何值,而不进行进一步的数字提升。

最新更新