Java Foundations
14/39
Bài 14 / 39~13 phútCú pháp Java & Kiểu dữ liệuLộ trình · chặng 02/21Miễn phí… lượt xem

Toán tử logic và bitwise — short-circuit, cờ bit và thứ tự ưu tiên

Nắm vững toán tử logic và bitwise trong Java: cơ chế short-circuit null-safe, thao tác cờ bitmask, toán tử ba ngôi và bảng thứ tự ưu tiên biểu thức.

TL;DR: && và || evaluate short-circuit: vế phải bị bỏ qua khi vế trái đã quyết định được kết quả — đây là nền tảng của pattern null-safe s != null && s.isEmpty(). Ngược lại, & và | luôn tính cả hai vế, đồng thời là toán tử bitwise trên số nguyên — công cụ chuẩn cho flags/bitmask. Với shift: >> dịch phải giữ dấu, >>> điền 0 vào bit cao nhất. Ternary ? : gọn cho phép chọn 1-trong-2 giá trị để gán, nhưng nested ternary khó đọc hơn if/else. Và khi không chắc thứ tự ưu tiên toán tử: cứ thêm ngoặc — compiler không tốn thêm chi phí nào.

Bài trước bạn đã nắm toán tử số học, so sánh và gán. Bài này hoàn thành hệ thống toán tử Java với nhóm còn lại: logic (và cơ chế short-circuit đứng sau pattern null-safe kinh điển), bitwise/shift cho thao tác từng bit, ternary cho gán có điều kiện — và cuối cùng là bảng thứ tự ưu tiên để bạn biết Java tính một biểu thức theo trật tự nào.

1. Analogy mạch điện mô tả các toán tử logic và short-circuit như thế nào?

Hãy nghĩ về công tắc mạch điện: hai công tắc nối tiếp (AND) — phải cả hai bật thì đèn mới sáng. Nối song song (OR) — chỉ cần một cái bật. Đó là logical operators.

Và mạch điện có một "thợ điện lười" rất thông minh: ở mạch nối tiếp, thấy công tắc đầu tiên đang tắt thì khỏi cần kiểm tra công tắc thứ hai — đèn chắc chắn không sáng. Đó chính là short-circuit.

Đời thườngConcept
Hai công tắc nối tiếp&& — cả hai vế true mới true
Hai công tắc song song|| — một vế true là đủ
Thợ điện lười dừng kiểm tra sớmShort-circuit evaluation
Bảng cầu chì bật/tắt từng nhánhBitwise flags trên từng bit

2. Các toán tử logic và cơ chế short-circuit hoạt động ra sao?

OperatorÝ nghĩaKhi nào trueShort-circuit
&&AND logicCả hai vế true✅ Có
||OR logicÍt nhất một vế true✅ Có
!NOT logicĐảo ngược booleanN/A
&AND bitwise/logicCả hai vế true❌ Không
|OR bitwise/logicÍt nhất một vế true❌ Không
Java
boolean a = true, b = false;
System.out.println(a && b);  // false
System.out.println(a || b);  // true
System.out.println(!a);      // false

2.1 Short-circuit evaluation — bộ não lười

&& và || dừng sớm khi kết quả đã xác định được:

  • &&: nếu vế trái là false → kết quả chắc chắn false → không evaluate vế phải.
  • ||: nếu vế trái là true → kết quả chắc chắn true → không evaluate vế phải.

Sau khi tính vế trái, nếu vế trái đã đủ quyết định kết quả thì vế phải không chạy và trả kết quả ngay, ngược lại mới tính tiếp vế phải

Ứng dụng thực tế — null-safe check:

Java
String s = null;

// AN TOAN: neu s == null thi khong goi s.isEmpty() (short-circuit)
if (s != null && s.isEmpty()) {
    System.out.println("Chuoi rong");
}

// NGUY HIEM: & khong short-circuit -- luon evaluate ca hai ve
// if (s != null & s.isEmpty())  // NPE neu s == null!
Java
// Short-circuit trong OR: neu isAdmin() tra true, checkPermission() khong chay
boolean coQuyen = isAdmin() || checkPermission(userId);
💡 Cách nhớ — short-circuit

&& như bộ não lười khi xét điều kiện AND: "vế đầu đã sai rồi — thôi không cần xem tiếp".

|| cũng lười theo cách khác: "vế đầu đúng rồi — không cần xem tiếp".

Ngược lại & và | (bitwise) luôn tính cả hai vế — dùng khi bạn cần side effect của vế phải xảy ra bất kể kết quả.

2.2 ✅/❌ Khi nào dùng & vs &&?

Tình huốngDùng gìLý do
Kết hợp điều kiện boolean thông thường✅ &&Short-circuit an toàn hơn, hiệu quả hơn
Vế phải là biểu thức có thể null/throw✅ &&Tránh NPE khi vế trái đã loại trừ
Bitwise operation trên số nguyên✅ &Toán tử bitwise đúng mục đích
Cần vế phải LUÔN được evaluate (side effect)✅ &Ít gặp, thường là dấu hiệu cần refactor
Điều kiện boolean bình thường❌ &Không short-circuit, không cần thiết

Thử ngẫmbạn đang review một điều kiện dùng & thay vì && để so hai boolean trong pull request — bạn để reviewer duyệt luôn, hay yêu cầu sửa? Vì sao?

3. Toán tử ba ngôi ternary operator được sử dụng khi nào?

Syntax: condition ? valueIfTrue : valueIfFalse

Java
int diem = 75;
String ketQua = (diem >= 50) ? "Dat" : "Roi";
System.out.println(ketQua);  // Dat

// Thay the if/else don gian -- gon hon
int max = (a > b) ? a : b;

Khi nào KHÔNG nên dùng ternary:

Java
// TRANH: nested ternary -- kho doc
String muc = (diem >= 90) ? "Xuat sac" : (diem >= 70) ? "Gioi" : (diem >= 50) ? "Trung binh" : "Roi";

// NEN: if/else if ro rang hon
String muc;
if      (diem >= 90) muc = "Xuat sac";
else if (diem >= 70) muc = "Gioi";
else if (diem >= 50) muc = "Trung binh";
else                 muc = "Roi";
💡 Cách nhớ — ternary

Ternary phù hợp khi chọn 1 trong 2 giá trị đơn giản để gán. Khi logic phức tạp hoặc nested, dùng if/else rõ ràng hơn.

4. Các toán tử bitwise và dịch bit thao tác trên nhị phân như thế nào?

OperatorÝ nghĩaVí dụKết quả
&AND từng bit5 & 31
|OR từng bit5 | 37
^XOR từng bit5 ^ 36
~NOT từng bit (complement)~5-6
<<Left shift1 << 38
>>Arithmetic right shift (giữ dấu)-8 >> 1-4
>>>Logical right shift (điền 0)-8 >>> 12147483644
Java
int a = 5;  // binary: 0101
int b = 3;  // binary: 0011

System.out.println(a & b);   // 0001 = 1
System.out.println(a | b);   // 0111 = 7
System.out.println(a ^ b);   // 0110 = 6
System.out.println(~a);      // ...11111010 = -6 (two's complement)
System.out.println(1 << 3);  // 0001 << 3 = 1000 = 8 (nhan 2^3)
System.out.println(8 >> 1);  // 1000 >> 1 = 0100 = 4 (chia 2)

4.1 Use case thực tế — flags và bitmask

Bitwise operators phổ biến khi dùng các bit của một int như tập hợp flags (cờ):

Java
// Dinh nghia flags (moi flag la mot bit rieng)
static final int FLAG_READ    = 0b001;  // bit 0 = 1
static final int FLAG_WRITE   = 0b010;  // bit 1 = 2
static final int FLAG_EXECUTE = 0b100;  // bit 2 = 4

int quyen = FLAG_READ | FLAG_WRITE;  // 0b011 = 3 (co ca READ va WRITE)

// Kiem tra mot flag
boolean coRead = (quyen & FLAG_READ) != 0;    // true
boolean coExec = (quyen & FLAG_EXECUTE) != 0; // false

// Bat them flag
quyen |= FLAG_EXECUTE;  // them EXECUTE

// Tat flag
quyen &= ~FLAG_WRITE;   // xoa WRITE (AND voi NOT WRITE)

// Toggle flag
quyen ^= FLAG_READ;     // bat neu tat, tat neu bat
Java
// Kiem tra so chan: bit cuoi == 0
boolean laSoChan = (n & 1) == 0;

// Chia doi nhanh bang shift (chi dung voi so duong)
int halved = n >> 1;  // tuong duong n / 2 nhung nhanh hon

4.2 >> vs >>> — giữ dấu hay không?

Java
int negative = -8;  // binary: 11111111111111111111111111111000

System.out.println(negative >> 1);   // -4: dich phai giu bit dau (1)
System.out.println(negative >>> 1);  // 2147483644: dich phai dien 0 vao bit cao nhat
💡 Cách nhớ — >> vs >>>
  • >> (arithmetic): giữ nguyên dấu — dùng khi chia 2 số nguyên có dấu.
  • >>> (logical): luôn điền 0 — dùng khi cần xử lý bit pattern thô (hash function, network protocol), bất kể dấu.

Thử ngẫmhệ thống phân quyền của bạn đang dùng số nguyên làm bitmask cho dưới 32 quyền — nếu số quyền vượt 32, thiết kế này còn đứng vững không, và bạn chuyển sang gì?

5. Thứ tự ưu tiên toán tử trong Java được quy định ra sao?

Java evaluate theo thứ tự ưu tiên từ cao đến thấp. Các operator cùng mức thực hiện từ trái sang phải (trừ assignment từ phải sang trái):

Mức (cao → thấp)Operators
1 — Postfixx++, x--
2 — Prefix / Unary++x, --x, +x, -x, ~, !
3 — Multiplicative*, /, %
4 — Additive+, -
5 — Shift<<, >>, >>>
6 — Relational<, >, <=, >=, instanceof
7 — Equality==, !=
8 — Bitwise AND&
9 — Bitwise XOR^
10 — Bitwise OR|
11 — Logical AND&&
12 — Logical OR||
13 — Ternary? :
14 — Assignment=, +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, ^=, |=
Java
// Khong ngoac -- dua vao precedence
int result = 2 + 3 * 4;   // = 14 (3*4 truoc, roi cong 2)

// Ro rang hon voi ngoac
int result2 = 2 + (3 * 4); // = 14 -- cung ket qua, ro hon
int result3 = (2 + 3) * 4; // = 20 -- thay doi thu tu

// Ket hop comparison va logical
boolean check = x > 0 && x < 100;  // > va < truoc &&
💡 Cách nhớ — precedence

Khi nghi ngờ, dùng dấu ngoặc. Code có ngoặc rõ ràng hơn là code "đúng nhờ nhớ thứ tự". Ngoặc không tốn gì về performance — compiler optimize hết.

Thử ngẫmsếp bạn yêu cầu code "ngắn gọn, ít ngoặc thừa" — khi nào bạn vẫn cố tình thêm ngoặc dù compiler không bắt buộc, và lý do đó có thắng được yêu cầu kia không?

6. Mã nguồn ví dụ minh họa logic và bitwise hoạt động như thế nào?

Java
public class LogicBitwiseDemo {
    static final int FLAG_READ    = 0b001;
    static final int FLAG_WRITE   = 0b010;
    static final int FLAG_EXECUTE = 0b100;

    public static void main(String[] args) {

        // --- Short-circuit null safe ---
        String s = null;
        if (s != null && s.isEmpty()) {
            System.out.println("Chuoi rong");
        } else {
            System.out.println("s la null hoac co noi dung");
        }

        // --- Bitwise flags ---
        int permissions = FLAG_READ | FLAG_WRITE;
        System.out.println("Co READ: " + ((permissions & FLAG_READ) != 0));       // true
        System.out.println("Co EXECUTE: " + ((permissions & FLAG_EXECUTE) != 0)); // false

        // Kiem tra so chan bang bitwise
        for (int i = 0; i < 6; i++) {
            System.out.println(i + " la so " + ((i & 1) == 0 ? "chan" : "le"));
        }

        // --- Shift: giu dau vs dien 0 ---
        int negative = -8;
        System.out.println(negative >> 1);   // -4
        System.out.println(negative >>> 1);  // 2147483644

        // --- Ternary ---
        int score = 75;
        String result = (score >= 50) ? "Pass" : "Fail";
        System.out.println("Ket qua: " + result);
    }
}

7. Bảng tổng hợp các toán tử logic và bitwise gồm những gì?

NhómOperatorsOperandTrả vềGhi chú
Logical&& || !booleanbooleanShort-circuit
Bitwise/logical& | ^ ~int/long/booleanint/long/booleanKhông short-circuit
Shift<< >> >>>int/longint/long>> giữ dấu, >>> điền 0
Ternary? :boolean + anysame as branchesGán có điều kiện gọn

8. Tài liệu Deep Dive Oracle quy định gì về logic và bitwise?

📚 Deep Dive Oracle (optional)

Spec chính thức Java 21:

Diễn giải đơn giản: §15.23/§15.24 nói rõ short-circuit là hành vi được spec đảm bảo, không phải optimization tuỳ JVM — bạn có thể dựa vào nó cho null-safe check. §15.22 giải thích vì sao &/| dùng được cho cả boolean lẫn integer: với boolean chúng là logic không short-circuit, với integer chúng là phép AND/OR trên từng bit.

Đọc thêm: Byte order và thao tác bit — góc nhìn phần cứng của &, |, ^, shift: vì sao chúng là phép toán rẻ nhất mà CPU thực thi trực tiếp trên từng bit.

9. Điểm cốt lõi cần nhớ về logic, bitwise và thứ tự ưu tiên là gì?

  • Cơ chế Short-circuit: && và || bỏ qua vế phải khi vế trái đã chốt kết quả, cho phép viết an toàn s != null && s.isEmpty().
  • Thao tác cờ bitmask: Bật bit bằng |=, kiểm tra bằng (x & FLAG) != 0, tắt bit bằng &= ~FLAG, và đảo bit bằng ^=.
  • Dịch bit giữ dấu vs điền 0: >> bảo toàn bit dấu âm, trong khi >>> luôn điền 0 vào vị trí cao nhất.
  • Thứ tự ưu tiên: Không cố nhớ toàn bộ bảng ưu tiên; luôn bao bọc các nhóm biểu thức con bằng dấu ngoặc ().

10. Tự kiểm tra kiến thức về toán tử logic và bitwise như thế nào?

Tự kiểm tra
0/5 câu đã trả lời
  1. Q1
    Đoạn sau an toàn hay có thể NPE? Vì sao?
    String s = getInput();  // co the tra null
    if (s != null && s.length() > 0) { ... }
  2. Q2
    Khi nào dùng & thay vì && với hai vế boolean? Vì sao trường hợp đó hiếm gặp?
  3. Q3
    (quyen & FLAG_READ) != 0 làm gì? Giải thích từng bước bitwise.
  4. Q4
    Với int negative = -8; — negative >> 1 và negative >>> 1 cho kết quả khác nhau thế nào? Vì sao >>> ra một số dương rất lớn?
  5. Q5
    Cho biết: 2 + 3 * 4 = bao nhiêu? Tại sao không phải 20?

Bài tiếp theo: Ép kiểu — widening, narrowing, autoboxing và safe cast patterns

Bài này có giúp bạn hiểu bản chất không?

Bài này đáng gửi cho bạn học cùng?

Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.

Lộ trình Junior Java Backend Developer

Chặng 2/21 · Lập trình từ số 0 với Java — bài 14/32 của chặng

Thảo luận & góp ý

Hỏi đáp về bài này

Bài tiếp theo

Ép kiểu trong Java: Widening, Narrowing và Safe Cast