為什么阿里編程規(guī)范使用三目運(yùn)算符類型必須一致

三目運(yùn)算是我們?nèi)粘i_發(fā)中經(jīng)常用到的一個(gè)運(yùn)算符號.它可以讓我們很優(yōu)雅地根據(jù)條件對一個(gè)變量進(jìn)行賦值,靈活又優(yōu)雅,但稍微不慎就會導(dǎo)致空指針異常.
首先我們來看一下阿里編程規(guī)范中的例子:

    @GetMapping("/v1")
    public String v1() {
        Integer a = 1;
        Integer b = 2;
        Integer c = null;
        Boolean flag = false;
        // a * b 的結(jié)果是 int 類型,那么 c 會強(qiáng)制拆箱成 int 類型,拋出 NPE 異常
        Integer result = (flag ? a * b : c);
        return "hello world";
    }

調(diào)用這段代碼一不小心就會因?yàn)閖ava的自動包裝引起的NPE異常,為了保證類型一致,編譯器在編譯的時(shí)候會幫我們隱式調(diào)用,這些細(xì)節(jié)點(diǎn)我們得閱讀class字節(jié)碼才可以知道得
我們使用idea查看v1方法的字節(jié)碼并借閱JVM虛擬機(jī)指令表可以了解到一些細(xì)節(jié)

  public v1()Ljava/lang/String;
  @Lorg/springframework/web/bind/annotation/GetMapping;(value={"/v1"})
   L0     
    LINENUMBER 17 L0         
    ICONST_1
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 1
  //  第17行  步驟L0
  //  1 將一個(gè)int類型值1放入棧頂
  //  2 調(diào)用Integer.valueOf方法將棧頂int 1轉(zhuǎn)換為Interger 1 并賦值給第1個(gè)本地變量
   L1
    LINENUMBER 18 L1
    ICONST_2
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 2
  //  第18行  步驟L1
  //  1 將一個(gè)int類型值2放入棧頂
  //  2 調(diào)用Integer.valueOf方法將棧頂int 2轉(zhuǎn)換為Interger 2 并賦值給第2個(gè)本地變量
   L2
    LINENUMBER 19 L2
    ACONST_NULL
    ASTORE 3
  // 第19行 步驟L2
  // 將null賦值給本地第3個(gè)本地變量
   L3
    LINENUMBER 20 L3
    ICONST_0
    INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;
    ASTORE 4
 // 第20行 步驟L3
//  將一個(gè)int類型值0放入棧頂并調(diào)用Boolean.valueOf方法轉(zhuǎn)換為Boolean false,并賦值給本地第4個(gè)變量
   L4
    LINENUMBER 22 L4
    ALOAD 4
    INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z
    IFEQ L5
    ALOAD 1
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    ALOAD 2
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    IMUL
    GOTO L6
   L5
   FRAME FULL [com/wkx/study/controller/TestController java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Boolean] []
    ALOAD 3
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
   L6
   FRAME SAME1 I
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 5
// 步驟 L4到L6是三目運(yùn)算符的字節(jié)碼類似于if else表達(dá)句
//  1 將本地第四個(gè)變量轉(zhuǎn)換為boolean類型
//  2 如果上一步轉(zhuǎn)換的boolean類型值為true的話
//  2.1 將本地第1跟第2個(gè)變量取出并調(diào)用Integer.intValue拆箱變?yōu)閕nt
//  2.2 將這兩個(gè)值進(jìn)行計(jì)算,并將計(jì)算結(jié)果裝箱賦值給第5個(gè)本地變量
//  3 如果為false的話 
//  3.1 將本地第3個(gè)變量拆箱轉(zhuǎn)為int
//  3.2 將上一步拆箱獲取的int在裝箱轉(zhuǎn)為Integer
   L7
    LINENUMBER 23 L7
    LDC "hello world"
    ARETURN

我們從上面的字節(jié)碼知道
1 兩個(gè)Integer進(jìn)行乘法運(yùn)算的時(shí)候會先轉(zhuǎn)為int來進(jìn)行計(jì)算,因?yàn)镮nteger不具備這個(gè)能力
2 三目運(yùn)算符其實(shí)在轉(zhuǎn)為字節(jié)碼中相當(dāng)于一個(gè)if else操作(如果上面例子的flag是true的話就不會NPE異常了)
3 在進(jìn)行三目運(yùn)算符的時(shí)候,編譯器為了保證類型一致會將冒號前后的保證類型轉(zhuǎn)為基本數(shù)據(jù)類型(將上面的例子改為 Integer k = Boolean ? int : Integer;也會將先拆箱轉(zhuǎn)為int再轉(zhuǎn)裝箱轉(zhuǎn)為Integer )

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容