1. Giới thiệu
Hãy bắt đầu với một phép so sánh đời thường. Hãy tưởng tượng một công thức nấu ăn:
Trộn bột, trứng và đường, đánh, thêm bơ, đánh lần nữa.
Nghe có vẻ lạ? Bây giờ hãy tưởng tượng rằng giữa các từ “đánh” và “thêm” có dấu phẩy hoặc dấu ngoặc. Thứ tự thao tác lập tức trở nên rõ ràng hơn.
Trong lập trình cũng tương tự khi bạn viết một biểu thức phức tạp:
boolean result = a > 0 && b < 10 || c == 3;
Thứ tự như thế nào? Cái gì được tính trước: a > 0 && b < 10, rồi đến || c == 3? Hay ngược lại?
Nếu không có thứ tự tính toán rõ ràng, máy tính có thể “trộn nhầm nguyên liệu”, và kết quả sẽ bất ngờ.
2. Độ ưu tiên của toán tử trong Java
Java (cũng như hầu hết các ngôn ngữ lập trình) sử dụng một bảng độ ưu tiên toán tử xác định.
Toán tử có độ ưu tiên cao hơn sẽ được thực hiện trước toán tử có độ ưu tiên thấp hơn.
Hãy xem phần quan trọng nhất của bảng này (đối với biểu thức điều kiện):
| Toán tử | Mô tả | Độ ưu tiên |
|---|---|---|
|
Dấu ngoặc | cao nhất |
|
Logic "NOT" | cao |
|
Bằng / không bằng | trung bình |
|
So sánh | trung bình |
|
Logic "AND" | thấp hơn |
|
Logic "OR" | thấp hơn nữa |
(Còn có các toán tử số học — chúng có độ ưu tiên cao hơn các toán tử logic.)
Quy tắc chính
Toán tử “AND” (&&) có độ ưu tiên cao hơn “OR” (||),
tức là trước tiên sẽ tính “AND”, sau đó “OR”. Không phải ngẫu nhiên AND là phép nhân logic, còn OR là phép cộng.
Sơ đồ khối đánh giá độ ưu tiên của điều kiện
graph LR
A["a > 0"] --&&--> B["b < 10"]
B --||--> C["c == 3"]
(Trong thực tế: a > 0 && b < 10 || c == 3 — trước hết tính a > 0 && b < 10, rồi kết quả đó được so sánh với c == 3 thông qua ||.)
3. Hướng kết hợp của toán tử: từ trái sang phải và ngược lại
Ngoài độ ưu tiên, còn có một khái niệm: tính kết hợp.
Đây là quy tắc xác định hướng tính toán khi các toán tử “đứng cạnh nhau” và có cùng độ ưu tiên.
Ví dụ:
boolean a = true, b = false, c = true;
boolean result = a && b && c;
Câu hỏi: sẽ được tính như thế nào?
Trả lời: tính kết hợp của && là từ trái sang phải.
Nghĩa là, trước a && b, rồi kết quả đó với c.
Áp dụng cho điều kiện:
| Toán tử | Tính kết hợp |
|---|---|
|
từ trái sang phải |
|
từ phải sang trái |
4. Dấu ngoặc — người bạn tốt nhất của bạn trong các điều kiện phức tạp
Đây là lúc phép màu (và cứu cánh) xuất hiện. Khi bạn viết biểu thức, dấu ngoặc thay đổi độ ưu tiên và làm cho mã của bạn rõ ràng, an toàn hơn.
Ví dụ 1 (không có ngoặc):
// Chúng ta muốn: "Nếu người dùng là người trưởng thành và là công dân, hoặc nếu họ có thẻ đặc biệt"
boolean isAdult = age >= 18;
boolean isCitizen = country.equals("Belarus");
boolean hasPermit = hasSpecialPass == true;
if (isAdult && isCitizen || hasPermit)
{
System.out.println("Truy cập được phép!");
}
Java đánh giá như sau:
Trước hết tính isAdult && isCitizen, sau đó so sánh kết quả với hasPermit bằng ||.
- Giả sử isAdult = true, isCitizen = false, hasPermit = true
- isAdult && isCitizen → true && false → false
- false || true → true
Tức là, nếu người đó có thẻ đặc biệt, vẫn sẽ được cho qua.
Còn nếu không có thẻ đặc biệt nhưng là công dân đã trưởng thành — cũng sẽ được cho qua.
Ví dụ 2 (có ngoặc):
if (isAdult && (isCitizen || hasPermit))
{
System.out.println("Truy cập được phép!");
}
Bây giờ chương trình trước tiên kiểm tra: isCitizen || hasPermit, sau đó kết hợp kết quả đó với isAdult.
Nghĩa là bạn cần phải là người trưởng thành và (hoặc là công dân, hoặc có thẻ đặc biệt).
Một khác biệt nhỏ ở dấu ngoặc — khác biệt lớn về logic!
GO TO FULL VERSION