Java中短路運算符與邏輯運算符示例詳解
1、邏輯運算符(部分)
符號 | 名稱 |
---|---|
&& | 短路與運算符 |
|| | 短路或運算符 |
& | 與運算符 |
| | 或運算符 |
對於理工科學習者來說,邏輯運算是較為基礎的概念,通常會在大一的離散數學課程中有所瞭解。在Java以及更多C-Like語言中,&和|會分別表示邏輯運算中的與、或,他們的運算結果與我們在數學書中所學的邏輯運算規則並無差異。但是,在實際編程的過程中,我們反而會更多使用&&和||,甚至不少同學都不瞭解&、|兩個運算符。那麼,這究竟是為什麼呢?
2、短路運算符
讓我們來回到最初學習邏輯運算時解決問題的真值表,以“或運算”為例:
a | b | 結果 |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
a和b中,隻要至少有一個為true,最終輸出的結果則為true。那麼,從算法優化的角度來思考問題的話,我們為瞭經過最少步驟還能輸出可靠的結果,我們便可以把“或運算”定義為,有一個true,就輸出true。
由此,“或運算”可以被優化為:從左向右,遇到有一個佈爾表達式為true,則返回true,不進行之後的運算。
與之相似的,“與運算”可以被優化為:從左向右,遇到有一個佈爾表達式為false,則返回false,不進行之後的運算。
故此,短路運算符被設計瞭出來。但為瞭兼顧“執行命令並返回”、“純粹的數學計算”等多種應用場景,傳統的非短路邏輯運算符也沒有被短路邏輯運算符而取代。
此外,對於連寫的短路運算符,如func1()||func2()||func3()||func4(),編譯器也會為此優化,我們不妨來閱讀這一部分的字節碼來驗證這個結論:
public static void main(String[] args) { boolean b1 = func1() || func2() || func3() || func4(); System.out.println("------------------"); boolean b2 = func1() | func2() | func3() | func4(); } // func1() - func4() here
短路“或”的字節碼如下:
0: invokestatic #7 // Method func1:()Z 3: ifne 24 6: invokestatic #13 // Method func2:()Z 9: ifne 24 12: invokestatic #16 // Method func3:()Z 15: ifne 24 18: invokestatic #19 // Method func4:()Z 21: ifeq 28 24: iconst_1 25: goto 29 28: iconst_0 29: istore_1
3行、9行、15行的ifne是將棧頂元素與0(false)相比,如果不為false則跳轉到24行將常量1(true)入棧,完成賦值,會跳過其餘的執行。直到最後21行,才將最後方法結果的值再與0相比,如果還是0,則將常量0入棧,完成賦值。
普通“或”等字節碼如下:
38: invokestatic #7 // Method func1:()Z 41: invokestatic #13 // Method func2:()Z 44: ior 45: invokestatic #16 // Method func3:()Z 48: ior 49: invokestatic #19 // Method func4:()Z 52: ior 53: istore_2
則是普通的或運算,無跳轉,順序執行最後賦值。
3、應用與陷阱
在最起初,筆者重新認識短路運算符是在這樣一段代碼中:
public LoginCheckDTO XxxLoginCheck(String password) { //some codes if ( password == null || password.length() == 0 ) { return LoginCheckDTO.EMPTY_PASSWORD; } //some codes }
當時筆者認為,如果password為null,在嘗試調用password.length()時,會拋出空指針異常,故此寫法不好。但在後來進行測試的時候,發現這樣寫並沒有問題,查閱相關資料便瞭解瞭短路運算符的概念。
在這個例子中,當執行password == null返回true的時候,隨後的表達式將不會被執行,就不存在拋出異常的情況瞭。這便是短路運算符較為常用的一個應用場景。
除此之外,我們還要警惕短路運算符導致的指令執行不完整。
譬如如下應用場景,我們希望利用條件語句來判斷所有燈在上一狀態是否都開著,並且無論如何我們希望最後打開所有的燈。但是我們錯誤使用瞭短路運算符:
public boolean checkAndTurnOnAll() { return checkAndTurnOn1() && checkAndTurnOn2(); } private boolean checkAndTurnOn1() { boolean check = check1(); turnOn1(); return check; } private boolean checkAndTurnOn2() { boolean check = check2(); turnOn2(); return check; }
在這個場景中,如果第一盞燈在上一個狀態是關閉狀態,在checkAndTurnOn1()中雖然會執行turnOn1(),並且返回false,但由於短路特性checkAndTurnOn2()並不會被執行,所以最後期望的看到所有的燈都被打開不一定會實現。這種情況應當使用&。
總結
到此這篇關於Java中短路運算符與邏輯運算符的文章就介紹到這瞭,更多相關Java短路運算符與邏輯運算符內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!