首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 邏輯運算符 & 與 && 核心區別:短路求值與副作用陷阱

     編輯:Java 相關知識

& 和 && 均為邏輯 AND 運算符,但求值策略本質不同:&& 具備短路特性,& 為全評估。本文通過字節碼、執行流程、副作用陷阱三個維度深度對比,並給出選用原則。

一、語法與類型

運算符名稱操作數類型結果類型
&邏輯 AND / 位 ANDboolean / 整數boolean / 整數
&&條件 AND (短路)booleanboolean

關鍵:& 用於 boolean 時為邏輯 AND,用於整數時為按位 AND;&& 僅支持 boolean。

二、執行流程對比

代碼示例


// 測試 & 全評估
public static void testAnd() {
    int i = 3;
    if ((i++ > 5) & (i++ < 9)) {  // 兩個條件都執行
        System.out.println("if body");
    }
    System.out.println("final i = " + i); // 輸出 5
}

// 測試 && 短路
public static void testShortCircuit() {
    int i = 3;
    if ((i++ > 5) && (i++ < 9)) { // 第一個 false,第二個不執行
        System.out.println("if body");
    }
    System.out.println("final i = " + i); // 輸出 4
}

執行軌跡分析

步驟& (全評估)&& (短路)
初始 i33
評估左側 i++ > 53>5=false, i→43>5=false, i→4
是否評估右側是否 (短路)
評估右側 i++ < 94<9=true, i→5跳過
if 條件結果false & true = falsefalse
最終 i54

三、字節碼層面驗證 (javap -c)


// & 版本關鍵字節碼
iload_1        // load i
iinc 1, 1      // i++
iconst_5
if_icmpgt L1   // >5 跳轉
iconst_0       // false
goto L2
L1: iconst_1   // true
L2: iload_1    // load i (再次)
iinc 1, 1      // i++ (第二次自增)
bipush 9
if_icmplt L3   // <9 跳轉
iconst_0
goto L4
L3: iconst_1
L4: iand       // 邏輯 AND (位運算)
ifeq L5        // false 跳過 if 體

// && 版本關鍵字節碼
iload_1
iinc 1, 1
iconst_5
if_icmpgt L1
iconst_0
goto L2
L1: iconst_1
L2: ifeq L3    // 關鍵:左側 false 直接跳轉到 L3 (跳過右側評估)
... 右側評估代碼 ...
L3: ifeq L4
... if 體 ...

核心差異:&& 編譯為兩次條件跳轉,左側 false 直接跳過右側代碼塊;& 編譯為完整評估雙方再 iand。

四、副作用陷阱實戰案例

4.1 方法調用副作用


boolean checkAndLog(String label) {
    System.out.println("Checking " + label);
    return true;
}

// 使用 &
if (checkAndLog("A") & checkAndLog("B")) { ... }
// 輸出: Checking A / Checking B (兩個都執行)

// 使用 &&
if (checkAndLog("A") && checkAndLog("B")) { ... }
// 輸出: Checking A (B 不執行)

4.2 空指針防護 (經典模式)


String str = null;
// 安全:短路防止 NPE
if (str != null && str.length() > 0) { ... }

// 危險:全評估導致 NPE
if (str != null & str.length() > 0) { ... } // 拋出 NullPointerException

4.3 資源檢查與獲取


// 短路模式:檢查並獲取
if ((resource = pool.acquire()) != null && resource.isValid()) {
    use(resource);
}

// 全評估模式:即使獲取失敗也會執行 isValid() → NPE
if ((resource = pool.acquire()) != null & resource.isValid()) { ... }

五、位運算場景:& 的正統用武之地


// 權限掩碼檢查
int permission = user.getPermission();
if ((permission & PERMISSION_WRITE) != 0) { // 檢查寫權限位
    allowWrite();
}

// 奇偶判斷
if ((num & 1) == 1) { isOdd(); }

// 清除標誌位
flags &= ~FLAG_DEBUG;

// 快速取模 (2的冪次)
int mod = value & (size - 1); // 等價 value % size, size為2的冪

六、選用原則總結

場景推薦運算符理由
邏輯判斷、條件檢查&&短路提升性能、防護 NPE、避免副作用
需要所有條件副作用執行&確保所有方法調用/賦值執行
位掩碼、權限位操作&按位 AND 語義
數學運算優化&位運算替代取模/除法
代碼可讀性&&主流習慣,意圖清晰

七、面試陷阱題


// 輸出什麼?
int x = 0;
if (true & (x++ > 0)) System.out.println("A");
System.out.println(x); // 輸出 1

int y = 0;
if (true && (y++ > 0)) System.out.println("B");
System.out.println(y); // 輸出 0 (短路,y++ 不執行)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved