Đoản mạch toán tử logic Java


99

Tập hợp nào là đoản mạch, và chính xác nghĩa là biểu thức điều kiện phức tạp bị đoản mạch là gì?

public static void main(String[] args) {
  int x, y, z;

  x = 10;
  y = 20;
  z = 30;

  // T T
  // T F
  // F T
  // F F

  //SET A
  boolean a = (x < z) && (x == x);
  boolean b = (x < z) && (x == z);
  boolean c = (x == z) && (x < z);
  boolean d = (x == z) && (x > z);
  //SET B    
  boolean aa = (x < z) & (x == x);
  boolean bb = (x < z) & (x == z);
  boolean cc = (x == z) & (x < z);
  boolean dd = (x == z) & (x > z);

}

Câu trả lời:


243

Các &&||các nhà khai thác "ngắn mạch", có nghĩa là họ không đánh giá bên tay phải nếu nó không phải là cần thiết.

Các toán tử &|, khi được sử dụng như các toán tử logic, luôn đánh giá cả hai bên.

Chỉ có một trường hợp đoản mạch đối với mỗi người vận hành và đó là:

  • false && ...- không cần biết phía bên phải là gì vì kết quả chỉ có thể là falsebất kể giá trị ở đó
  • true || ...- không cần biết phía bên phải là gì vì kết quả chỉ có thể là truebất kể giá trị ở đó

Hãy so sánh hành vi trong một ví dụ đơn giản:

public boolean longerThan(String input, int length) {
    return input != null && input.length() > length;
}

public boolean longerThan(String input, int length) {
    return input != null & input.length() > length;
}

Phiên bản thứ 2 sử dụng toán tử không đoản mạch &và sẽ ném NullPointerExceptionnếu inputnull, nhưng phiên bản thứ nhất sẽ quay trở lại falsemà không có ngoại lệ.


9
Tôi chỉ muốn mở rộng câu trả lời này một chút. Toán tử & = là cách viết tắt của biểu thức x = x &, do đó KHÔNG phải là ngắn mạch. Điều này cũng đúng với toán tử | =.
Stormcloud

11
Một điều tôi muốn nhấn mạnh, | và & là toán tử nhị phân, trong khi && và || là các toán tử điều kiện (logic). | và & làm việc nhiều hơn là chỉ boolean, trong khi && và || chỉ hoạt động trên boolean.
Một câu chuyện thần thoại vào

1
Chúng không chỉ không đánh giá biểu thức ở phía bên tay phải mà mã còn không được thực thi để có bất kỳ thứ gì để đánh giá. Đây là một điểm quan trọng để hiểu nếu một tác dụng phụ sẽ được tạo ra.
mckenzm

@mckenzm Sự khác biệt giữa được đánh giá và thực thi là gì?
Kronen

@Kronen Execution có thể dẫn đến nhiều hơn đánh giá và tạo ra tác dụng phụ, chẳng hạn như ngoại lệ hoặc sự chậm trễ, tôi sẽ trả tiền không liên quan đến ví dụ này.
mckenzm

9

SET A sử dụng toán tử boolean ngắn mạch.

'Đoản mạch' có nghĩa là gì trong ngữ cảnh của toán tử boolean là đối với một tập hợp các boolean b1, b2, ..., bn, các phiên bản ngắn mạch sẽ ngừng đánh giá ngay khi boolean đầu tiên là true (|| ) Hay sai (&&).

Ví dụ:

// 2 == 2 will never get evaluated because it is already clear from evaluating
// 1 != 1 that the result will be false.
(1 != 1) && (2 == 2)

// 2 != 2 will never get evaluated because it is already clear from evaluating
// 1 == 1 that the result will be true.
(1 == 1) || (2 != 2)

Hãy xác định rằng đây là trường hợp cho &&, ||các công trình khác nhau và sẽ chấm dứt đánh giá trên các toán hạng đầu tiên mà trả về true;)
FGE

1
Trong thực tế, để được thực sự hoàn chỉnh, tất cả các &&, ||, &|đánh giá các trái sang phải. Đối với tập hợp các boolean b1, b2, ..., bn, các phiên bản ngắn mạch sẽ ngừng đánh giá khi giá trị đầu tiên của các boolean này là true ( ||) hoặc false ( &&). Bah, nguyên tắc là ở đó;)
fge

@fge: Vâng, tất nhiên là bạn đúng. Định nghĩa của bạn chính xác hơn của tôi. Tôi đã cập nhật câu trả lời của tôi với câu trong bình luận của bạn. Tôi hy vọng bạn không phiền.
afrischke

Đừng lo lắng, kiến ​​thức không có giá trị nếu nó không được chia sẻ.
fge

4

Ngắn mạch có nghĩa là người vận hành thứ hai sẽ không được kiểm tra nếu người điều hành thứ nhất quyết định kết quả cuối cùng.

Vd: Biểu thức là: Đúng || Sai

Trong trường hợp của ||, tất cả những gì chúng ta cần là một bên là Đúng. Vì vậy, nếu bên tay trái là đúng, không có ích gì khi kiểm tra bên tay phải, và do đó điều đó sẽ không được kiểm tra chút nào.

Tương tự, Sai && Đúng

Trong trường hợp &&, chúng ta cần cả hai bên đều Đúng. Vì vậy, nếu bên tay trái là Sai, không có ích gì khi kiểm tra bên tay phải, câu trả lời phải là Sai. Và do đó điều đó sẽ không được kiểm tra.


4
boolean a = (x < z) && (x == x);

Loại này sẽ ngắn mạch, có nghĩa là nếu (x < z)đánh giá là sai thì sau đó không được đánh giá, asẽ là sai, nếu không &&cũng sẽ đánh giá (x == x).

& là một toán tử bitwise, nhưng cũng là một toán tử boolean AND không gây ngắn mạch.

Bạn có thể kiểm tra chúng bằng một số thứ như sau (xem phương thức được gọi bao nhiêu lần trong mỗi trường hợp):

public static boolean getFalse() {
    System.out.println("Method");
    return false;
}

public static void main(String[] args) {
    if(getFalse() && getFalse()) { }        
    System.out.println("=============================");        
    if(getFalse() & getFalse()) { }
}

-1 câu trả lời của bạn cho thấy &chỉ một nhà điều hành Bitwise, nhưng điều đó là không đúng. Nó cũng là một toán tử boolean "hoặc".
Bohemian

@Bohemian: Cảm ơn bạn đã quan tâm. true & falseđánh giá thành false. Bạn có thể vui lòng giải thích điều này "boolean" hoặc "toán tử" không? Có thể là tôi không hiểu những gì bạn đang cố gắng nói.
Bhesh Gurung

Xin lỗi - ý tôi là boolean AND, không phải OR! tức true & falselà cú pháp hợp lệ. -1 đã xóa :)
Bohemian

4

Nói một cách dễ hiểu, đoản mạch có nghĩa là ngừng đánh giá một khi bạn biết rằng câu trả lời không thể thay đổi được nữa. Ví dụ: nếu bạn đang đánh giá một chuỗi logic ANDvà bạn phát hiện ra một chuỗi FALSEở giữa chuỗi đó, bạn biết kết quả sẽ là sai, bất kể giá trị của các biểu thức còn lại trong chuỗi là gì. Tương tự đối với chuỗi ORs: khi bạn phát hiện ra a TRUE, bạn biết ngay câu trả lời và vì vậy bạn có thể bỏ qua việc đánh giá phần còn lại của các biểu thức.

Bạn cho Java biết rằng bạn muốn đoản mạch bằng cách sử dụng &&thay vì &||thay vì |. Bộ đầu tiên trong bài viết của bạn là đoản mạch.

Lưu ý rằng đây không chỉ là một nỗ lực để tiết kiệm một vài chu kỳ CPU: trong các biểu thức như thế này

if (mystring != null && mystring.indexOf('+') > 0) {
    ...
}

đoản mạch có nghĩa là sự khác biệt giữa hoạt động chính xác và sự cố (trong trường hợp chuỗi của tôi là rỗng).


2

Java cung cấp hai toán tử Boolean thú vị không có trong hầu hết các ngôn ngữ máy tính khác. Các phiên bản thứ cấp của AND và OR được gọi là các toán tử logic ngắn mạch . Như bạn có thể thấy từ bảng trước, toán tử OR cho kết quả là true khi A đúng, bất kể B là gì.

Tương tự, toán tử AND cho kết quả false khi A sai, bất kể B là gì. Nếu bạn sử dụng các dạng ||&&thay vì dạng |&của các toán tử này, Java sẽ không bận tâm đến việc đánh giá toán hạng bên phải một mình. Điều này rất hữu ích khi toán hạng bên phải phụ thuộc vào toán hạng bên trái là true hoặc false để hoạt động đúng.

Ví dụ: đoạn mã sau đây cho thấy cách bạn có thể tận dụng đánh giá lôgic ngắn mạch để đảm bảo rằng phép toán phân chia sẽ hợp lệ trước khi đánh giá nó:

if ( denom != 0 && num / denom >10)

Vì dạng ngắn mạch của AND ( &&) được sử dụng, không có nguy cơ gây ra ngoại lệ thời gian chạy từ phép chia cho 0. Nếu dòng mã này được viết bằng một &phiên bản AND, thì cả hai bên sẽ phải được đánh giá, gây ra ngoại lệ thời gian chạy khi denombằng 0.

Thông lệ tiêu chuẩn là sử dụng các dạng ngắn mạch của AND và OR trong các trường hợp liên quan đến logic Boolean, để lại các phiên bản ký tự đơn dành riêng cho các phép toán bit. Tuy nhiên, có những trường hợp ngoại lệ cho quy tắc này. Ví dụ, hãy xem xét câu lệnh sau:

 if ( c==1 & e++ < 100 ) d = 100;

Ở đây, việc sử dụng một đơn vị &đảm bảo rằng phép toán tăng dần sẽ được áp dụng cho eviệc ccó bằng 1 hay không.


2

Logical OR: - trả về true nếu ít nhất một trong các toán hạng đánh giá là true. Cả hai toán hạng đều được đánh giá trước khi áp dụng toán tử OR.

Ngắn mạch HOẶC: - nếu toán hạng bên trái trả về true, nó trả về true mà không đánh giá toán hạng bên phải.


2

Có một vài điểm khác biệt giữa toán tử &&&toán tử. Sự khác biệt tương tự áp dụng cho |||. Điều quan trọng nhất cần lưu ý là &&là một logic điều hành mà chỉ áp dụng cho toán hạng boolean, trong khi &là một Bitwise điều hành áp dụng cho các loại nguyên cũng như các phép toán luận.

Với một phép toán logic, bạn có thể thực hiện đoản mạch vì trong một số trường hợp nhất định (như toán hạng đầu tiên của bản &&thể falsehoặc toán hạng đầu tiên của bản ||thể true), bạn không cần đánh giá phần còn lại của biểu thức. Điều này rất hữu ích để thực hiện những việc như kiểm tra nulltrước khi truy cập một tệp hoặc phương thức và kiểm tra các số không tiềm năng trước khi chia cho chúng. Đối với một biểu thức phức tạp, mỗi phần của biểu thức được đánh giá đệ quy theo cùng một cách. Ví dụ, trong trường hợp sau:

(7 == 8) || ( (1 == 3) && (4 == 4))

Chỉ những phần được nhấn mạnh mới được đánh giá. Để tính toán ||, trước tiên hãy kiểm tra xem 7 == 8true. Nếu đúng như vậy, phía bên tay phải sẽ bị bỏ qua hoàn toàn. Bên tay phải chỉ kiểm tra nếu 1 == 3false. Vì nó là, 4 == 4không cần phải được kiểm tra và toàn bộ biểu thức đánh giá false. Nếu bên tay trái là true, ví dụ 7 == 7thay vì 7 == 8, toàn bộ bên tay phải sẽ bị bỏ qua vì toàn bộ ||biểu thức sẽ truekhông phân biệt.

Với thao tác bitwise, bạn cần đánh giá tất cả các toán hạng bởi vì bạn thực sự chỉ đang kết hợp các bit. Boolean thực sự là một số nguyên một bit trong Java (bất kể bên trong hoạt động như thế nào), và thật là ngẫu nhiên khi bạn có thể thực hiện đoản mạch cho các toán tử bit trong một trường hợp đặc biệt. Lý do mà bạn không thể đoản mạch một số nguyên &hoặc |phép toán chung là một số bit có thể được bật và một số có thể bị tắt trong một trong hai toán hạng. Một cái gì đó giống như kết 1 & 2quả bằng không, nhưng bạn không có cách nào biết được điều đó mà không đánh giá cả hai toán hạng.


1
if(demon!=0&& num/demon>10)

Vì dạng ngắn mạch của AND (&&) được sử dụng, không có nguy cơ gây ra ngoại lệ thời gian chạy khi giá trị quỷ bằng 0.

Tham khảo Java 2 phiên bản thứ năm của Herbert Schildt

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.