写点什么

Java 踩坑之三目运算符类型转换

作者:lambochen
  • 2023-01-28
    浙江
  • 本文字数:2106 字

    阅读完需:约 7 分钟

博客搬家,原 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 时,也是支持给引用类型赋值的。


特别的,我们关注到了基本类型和其封装类型,于是有了下述代码。


@Testpublic 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 嘛,这不科学。


我们再来尝试下另外一种写法:


@Testpublic 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

参考

关于三元运算符的类型转换问题

发布于: 刚刚阅读数: 3
用户头像

lambochen

关注

Stay hungry, stay foolish. 2019-02-28 加入

还未添加个人简介

评论

发布
暂无评论
Java踩坑之三目运算符类型转换_lambochen_InfoQ写作社区