博客搬家,原 blog:https://blog.csdn.net/chensanwa/article/details/100498077
1. 前言
相信各位 Javaer 对于三目运算符(三元运算符)都不陌生,较多情况下使用三目运算符即可节省一个 if-else 语句赋值的编写,笔者也是经常使用三目运算符,前段时间遇到了一点三目运算符的类型转换的坑,便在此记录一下。望更多的朋友能够避免,也加深我对三目运算符的理解。
2. 三目运算符使用
闲话不说,直接上代码。
/**
* 三目运算符使用
*/
public void ternaryOperator() {
boolean switchLog = true;
// 基本类型
int intValue = switchLog ? 1 : 0;
// 引用类型
String strValue = switchLog ? "true" : "false";
}
复制代码
三目运算符可表达为:布尔表达式 ? 表达式 1 : 表达式 2
布尔表达式:其结果决定三目运算符的分支情况表达式 1:当布尔表达式为 true,则执行表达式 2:当布尔表达式为 false,则执行
3. 类型转换
在三目运算符的使用过程中,即支持基本类型,也支持引用类型。值得注意的一点是,引用类型为 null 时,也是支持给引用类型赋值的。
特别的,我们关注到了基本类型和其封装类型,于是有了下述代码。
@Test
public void intInteger() {
boolean switchLog = true;
Integer oneExpre = null
Integer result = switchLog ? oneExpre : 0;
System.out.println(result);
}
复制代码
猜想下这个程序的 result 返回什么,是 null 么?为什么?
试着运行下测试,发现得到以下报错:
java.lang.NullPointerException
at club.chenlinghong.demo.ternaryoperator.TernaryOperatorDemo.intInteger(TernaryOperatorDemo.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70
复制代码
NPE,有意思,命名没有任何问题呀,就算是 switchLog 为 true 嘛,也就把 null 值赋给 result 嘛,这不科学。
我们再来尝试下另外一种写法:
@Test
public void intInteger() {
boolean switchLog = true;
Integer oneExpre = null;
Integer result = switchLog ? oneExpre : new Integer(0);
System.out.println(result);
}
复制代码
再次执行,居然没报错。result 为 null。
3.1 尝试着分析一下
报错的情况:
这种情况下,“表达式 1” 结果是 null,而“ 表达式 2 ” 是基本类型。大胆猜想一下,当执行时,先执行 “表达式 1” 的得到返回结果 null ,此时 null 是一个特殊的值,并不知道其“具体的类型”,然后尝试着和 “表达式 2” 进行统一类型,发现 “表达式 2” 是 int 类型,并进行强转或者封装类型转基本类型,报 NPE。
未报错的情况:
和报错情况不同的是,“表达式 2”本身就是 Integer 类型,封装类型本身支持 null 类型赋值,便省去了类型强转的步骤,则不报错。
4. 结论与思考
这是一个有趣的实验,同时也是一个很坑的点。对于这些细枝末节的知识点(坑点),可能在平时学习和编码中都很少遇到,但是在遇到的时候,可能需要查很久很久的代码才能找到。
注重知识点的累计,多一次在学习中踩坑,就少一次在生产上的事故,哈哈哈哈哈 ~ _ ~
5. 源码
Github 链接,欢迎 star,follow。
demo-springboot
参考
关于三元运算符的类型转换问题
评论