Java中三目運算符之類型轉換

前言

相信各位 Javaer 對於三目運算符(三元運算符)都不陌生,較多情況下使用三目運算符即可節省一個 if-else 語句賦值的編寫,筆者也是經常使用三目運算符,前段時間遇到了一點三目運算符的類型轉換的坑,便在此記錄一下。望更多的朋友能夠避免,也加深我對三目運算符的理解。

三目運算符使用

閒話不說,直接上代碼。

/**
 * 三目運算符使用
 */
public void ternaryOperator() {
    boolean switchLog = true;
    // 基本類型
    int intValue = switchLog ? 1 : 0;
    // 引用類型
    String strValue = switchLog ? "true" : "false";
}

三目運算符可表達爲:布爾表達式 ? 表達式1 : 表達式2

布爾表達式:其結果決定三目運算符的分支情況
表達式1:當布爾表達式爲 true,則執行
表達式2:當布爾表達式爲 false,則執行

類型轉換

在三目運算符的使用過程中,即支持基本類型,也支持引用類型。值得注意的一點是,引用類型爲 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。

在這裏插入圖片描述

嘗試着分析一下

報錯的情況:

這種情況下,“表達式1” 結果是 null,而“ 表達式2 ” 是基本類型。大膽猜想一下,當執行時,先執行 “表達式1” 的得到返回結果 null ,此時 null 是一個特殊的值,並不知道其“具體的類型”,然後嘗試着和 “表達式2” 進行統一類型,發現 “表達式2” 是 int 類型,並進行強轉或者封裝類型轉基本類型,報NPE。

未報錯的情況:

和報錯情況不同的是,“表達式2”本身就是 Integer 類型,封裝類型本身支持 null 類型賦值,便省去了類型強轉的步驟,則不報錯。

結論與思考

這是一個有趣的實驗,同時也是一個很坑的點。對於這些細枝末節的知識點(坑點),可能在平時學習和編碼中都很少遇到,但是在遇到的時候,可能需要查很久很久的代碼才能找到。

注重知識點的累計,多一次在學習中踩坑,就少一次在生產上的事故,哈哈哈哈哈 ~ _ ~

源碼

Github鏈接,歡迎star,follow。

demo-springboot

參考

關於三元運算符的類型轉換問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章