ความแตกต่างในตัวดำเนินการบูลีน: & vs && และ | เทียบกับ ||


คำตอบ:


134

สิ่งเหล่านี้คือตัวดำเนินการ AND และ bitwise OR

int a = 6; // 110
int b = 4; // 100

// Bitwise AND    

int c = a & b;
//   110
// & 100
// -----
//   100

// Bitwise OR

int d = a | b;
//   110
// | 100
// -----
//   110

System.out.println(c); // 4
System.out.println(d); // 6

ขอบคุณ Carlos ที่ชี้ให้เห็นส่วนที่เหมาะสมใน Java Language Spec ( 15.22.1 , 15.22.2 ) เกี่ยวกับพฤติกรรมที่แตกต่างกันของตัวดำเนินการตามอินพุต

เมื่ออินพุตทั้งสองเป็นบูลีนตัวดำเนินการจะถือว่าเป็นตัวดำเนินการตรรกะบูลีนและทำงานคล้ายกับตัวดำเนินการ Conditional-And ( &&) และ Conditional-Or ( ||) ยกเว้นข้อเท็จจริงที่ว่าพวกเขาไม่ลัดวงจรดังนั้นสิ่งต่อไปนี้จะปลอดภัย :

if((a != null) && (a.something == 3)){
}

มันไม่ใช่:

if((a != null) & (a.something == 3)){
}

"การลัดวงจร" หมายความว่าผู้ปฏิบัติงานไม่จำเป็นต้องตรวจสอบเงื่อนไขทั้งหมด ในตัวอย่างข้างต้น&&จะตรวจสอบเงื่อนไขที่สองก็ต่อเมื่อaไม่เป็นเช่นนั้นnull(มิฉะนั้นคำสั่งทั้งหมดจะส่งคืนเป็นเท็จและจะต้องสงสัยในการตรวจสอบเงื่อนไขต่อไปนี้) ดังนั้นคำสั่งของa.somethingจะไม่ยกข้อยกเว้นหรือถือว่า "ปลอดภัย .”

&ดำเนินการจะตรวจสอบทุกเงื่อนไขในประโยคเสมอดังนั้นในตัวอย่างข้างต้นa.somethingอาจได้รับการประเมินเมื่อaเป็นnullค่าจริงโดยเพิ่มข้อยกเว้น


1
ต้องการชี้แจง .. & จะคืน 1 ก็ต่อเมื่อทั้งสองเป็น 1? 101 & 001 จะเป็น 001? ขวา?
gideon

@giddy @Jonathon - ฉันอัปเดตค่านิยมเพื่อแสดงสถานการณ์นั้นให้ดีขึ้น
Justin Niessner

ไม่สมบูรณ์: พวกเขายังเป็นตัวดำเนินการทางตรรกะ (สำหรับบูลีน)
user85421

1
@ Carlos- ไม่พวกเขายังคงเป็นตัวดำเนินการระดับบิต พวกมันทำงานเหมือนกับตัวดำเนินการตรรกะที่ไม่ลัดวงจร มีความแตกต่าง
Justin Niessner

4
และอะไรคือตัวดำเนินการเชิงตรรกะที่ไม่ลัดวงจร? ตัวดำเนินการ & และ | (ถามโดย OP) คือ "Integer Bitwise Operators" (JLS 15.22.1) และ "Boolean Logical Operators" (JLS 15.22.2) หรือข้อกำหนดภาษา Java ผิดเกี่ยวกับเรื่องนั้น?
user85421

108

ฉันคิดว่าคุณกำลังพูดถึงความหมายเชิงตรรกะของตัวดำเนินการทั้งสองที่นี่คุณมีตารางประวัติย่อ:

boolean a, b;

Operation     Meaning                       Note
---------     -------                       ----
   a && b     logical AND                    short-circuiting
   a || b     logical OR                     short-circuiting
   a &  b     boolean logical AND            not short-circuiting
   a |  b     boolean logical OR             not short-circuiting
   a ^  b     boolean logical exclusive OR
  !a          logical NOT

short-circuiting        (x != 0) && (1/x > 1)   SAFE
not short-circuiting    (x != 0) &  (1/x > 1)   NOT SAFE

การประเมินการลัดวงจรการประเมินผลขั้นต่ำหรือการประเมินผลของ McCarthy (หลังจาก John McCarthy) เป็นความหมายของตัวดำเนินการบูลีนบางตัวในภาษาโปรแกรมบางตัวซึ่งอาร์กิวเมนต์ที่สองจะถูกเรียกใช้หรือประเมินเฉพาะในกรณีที่อาร์กิวเมนต์แรกไม่เพียงพอที่จะกำหนดค่าของ นิพจน์: เมื่ออาร์กิวเมนต์แรกของฟังก์ชัน AND ประเมินว่าเป็นเท็จค่าโดยรวมจะต้องเป็นเท็จ และเมื่ออาร์กิวเมนต์แรกของฟังก์ชัน OR ประเมินเป็นจริงค่าโดยรวมจะต้องเป็นจริง

ไม่ปลอดภัยหมายถึงตัวดำเนินการจะตรวจสอบทุกเงื่อนไขในประโยคเสมอดังนั้นในตัวอย่างข้างต้นอาจมีการประเมิน 1 / x เมื่อ x เป็นค่า 0 โดยยกข้อยกเว้น


1
@Torres - โปรดขยายคำตอบของคุณโดยอธิบาย "ไฟฟ้าลัดวงจร" และ "ปลอดภัย" นอกจากนี้ยัง "เป็นเอกสิทธิ์หรือ" และ "ตรรกะไม่" "ไม่ลัดวงจร" ด้วย? แล้วทำไมถึงเรียกว่า "logical not" แทนที่จะเป็น "boolean logical not"? และเหตุใด "ตรรกะ NOT" จึงไม่ถูกจัดกลุ่มด้วย "ตรรกะ AND" และ "ตรรกะหรือ" คำตอบที่ดี แต่ต้องทำงาน
tfmontague

@tfmontague ฉันได้อธิบายความหมายของการลัดวงจรแล้ว (โดยการแก้ไขคำตอบนี้) .. กำลังรอให้การแก้ไขของฉัน "ตรวจสอบโดยเพื่อน"
Taslim Oseni

"ไม่ปลอดภัย" เกี่ยวกับการไม่ลัดวงจรคืออะไร? ไม่น่าจะปลอดภัยไปกว่าการใช้ไฟฟ้าลัดวงจร? btw: คุณไม่ได้อธิบายคำว่า "ลัดวงจร" จริงๆ หมายความว่า "ไม่ลัดวงจร" ทุกส่วนจะได้รับการประเมินก่อนจากนั้นจึงใช้การทำงานของบูลีนในขณะที่การลัดวงจรการประเมินจะหยุดลงเมื่อนิพจน์แรกตรงตามเงื่อนไขเช่น (a || b) จะไม่ ประเมิน b ถ้า a เป็นจริงและหรือการดำเนินการจะกลับมาเป็นจริงไม่ว่า b จะเป็นอย่างไร
SCI

26

ฉันรู้ว่ามีคำตอบมากมายที่นี่ แต่พวกเขาทั้งหมดดูสับสนเล็กน้อย ดังนั้นหลังจากทำการค้นคว้าจากคู่มือการศึกษา Java oracle แล้วฉันก็ได้พบสถานการณ์ที่แตกต่างกันสามสถานการณ์ว่าเมื่อใดควรใช้ && หรือ & สามสถานการณ์เป็นตรรกะและ , บิตและและบูลและ

Logical AND: Logical AND (aka Conditional AND) ใช้ตัวดำเนินการ&& เป็นความหมายที่ลัดวงจร: ถ้าตัวถูกดำเนินการด้านซ้ายเป็นเท็จตัวถูกดำเนินการด้านขวาจะไม่ถูกประเมิน
ตัวอย่าง:

int x = 0;
if (false && (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); // "0"

ในตัวอย่างข้างต้นค่าที่พิมพ์ไปยังคอนโซลของ x จะเป็น 0 เนื่องจากตัวถูกดำเนินการตัวแรกในคำสั่ง if เป็นเท็จดังนั้น java จึงไม่จำเป็นต้องคำนวณ (1 == ++ x) ดังนั้น x จะไม่ถูกคำนวณ

Bitwise AND: Bitwise AND ใช้ตัวดำเนินการ& ใช้เพื่อ preform การดำเนินการแบบบิตตามค่า ง่ายกว่ามากที่จะดูว่าเกิดอะไรขึ้นโดยดูที่การดำเนินการกับเลขฐานสองเช่น:

int a = 5;     //                    5 in binary is 0101
int b = 12;    //                   12 in binary is 1100
int c = a & b; // bitwise & preformed on a and b is 0100 which is 4

ดังที่คุณเห็นในตัวอย่างเมื่อการแทนค่าไบนารีของตัวเลข 5 และ 12 เรียงต่อกันจากนั้นการจัดรูปแบบบิตและแบบล่วงหน้าจะสร้างเฉพาะเลขฐานสองที่ตัวเลขเดียวกันในทั้งสองจำนวนมี 1 ดังนั้น 0101 & 1100 == 0100 ซึ่งในฐานสิบคือ 5 & 12 == 4

บูลีนและ: ตอนนี้ตัวดำเนินการบูลีน AND ทำงานในลักษณะเดียวกันและแตกต่างกันไปทั้งในบิต AND และตรรกะ AND ฉันชอบคิดว่ามันเป็น preforming บิต AND ระหว่างสองค่าบูลีน (หรือบิต) ดังนั้นจึงใช้&ตัวดำเนินการ ค่าบูลีนอาจเป็นผลมาจากนิพจน์ตรรกะได้เช่นกัน

ส่งคืนค่าจริงหรือเท็จเช่นเดียวกับตรรกะ AND แต่ไม่เหมือนตรรกะ AND คือไม่ลัดวงจร เหตุผลก็คือเพื่อให้ preform นั้นบิตและมันต้องรู้ค่าของตัวถูกดำเนินการทั้งซ้ายและขวา นี่คืออดีต:

int x = 0;
if (false & (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); //"1"

ตอนนี้เมื่อรันคำสั่ง if นั้นนิพจน์ (1 == ++ x) จะถูกดำเนินการแม้ว่าตัวถูกดำเนินการด้านซ้ายจะเป็นเท็จ ดังนั้นค่าที่พิมพ์ออกมาสำหรับ x จะเป็น 1 เพราะมีการเพิ่มขึ้น

นอกจากนี้ยังใช้กับ Logical OR (||), bitwise OR (|) และ boolean OR (|) หวังว่าสิ่งนี้จะช่วยคลายความสับสน


to preform that bitwise AND, it must know the value of both left and right operandsสิ่งนี้ไม่ถูกต้องสำหรับฉัน เพื่อดำเนินการที่คุณไม่จำเป็นต้องรู้ว่าตัวถูกดำเนินการที่เหมาะสมเพื่อให้สามารถที่จะคิดออกผลถ้าตัวถูกดำเนินการทางด้านซ้ายคือBITWISE AND FALSEสิ่งที่คุณอธิบายนั้นถูกต้อง แต่เหตุผลที่คุณระบุไม่เป็นเช่นนั้นสำหรับฉันอย่างน้อย ..
Koray Tugay

7

ตัวดำเนินการ && และ || เป็นการลัดวงจรซึ่งหมายความว่าพวกเขาจะไม่ประเมินนิพจน์ทางขวามือหากค่าของนิพจน์ทางซ้ายเพียงพอที่จะกำหนดผลลัพธ์


7
-1 สำหรับบอก OP ในสิ่งที่เขารู้อยู่แล้วและไม่ตอบคำถามที่เขาถามจริง
Alnitak

5

& และ | ให้ผลลัพธ์เช่นเดียวกับ && และ || ตัวดำเนินการ ความแตกต่างคือพวกเขามักจะประเมินทั้งสองด้านของนิพจน์โดยที่ && และ || หยุดประเมินว่าเงื่อนไขแรกเพียงพอที่จะตัดสินผลลัพธ์หรือไม่


1
ผิด .... เพราะ&&มันจะประเมินผลลัพธ์ทั้งสองในขณะที่||ส่งกลับก็ต่อเมื่อเงื่อนไขแรกเป็นจริง
Buhake Sindi

1
ฮะ? && จะประเมินเฉพาะด้านขวามือของนิพจน์หากด้านซ้ายมือประเมินแล้วว่าเป็นจริง มิฉะนั้นจะหยุดประเมินเป็นข้อเท็จแรกโดยนัยหมายความว่าผลลัพธ์ไม่สามารถเป็นจริงได้ ดูjguru.com/faq/view.jsp?EID=16530
Brian Scott

1
( 2 & 4 )ประเมินfalseในขณะที่ประเมิน( 2 && 4 ) trueผลลัพธ์เดียวกันนั้นเป็นอย่างไร?
Piskvor ออกจากอาคาร

1
@Piskvor - ไม่ได้อยู่ใน Java! 2 & 4ผลลัพธ์เป็นจำนวนเต็มไม่ใช่บูลีน (ศูนย์ในกรณีนี้) 2 && 4จะไม่คอมไพล์ && ยอมรับเฉพาะบูลีน Java ไม่อนุญาตให้ผสม booleans และ ints: ศูนย์ไม่ได้false, falseไม่เป็นศูนย์ ...
user85421

1
@BuhakeSindi ผิด. สำหรับมันประเมินตัวถูกดำเนินการสองถ้าตัวถูกดำเนินการแรกคือ&& true
Marquis of Lorne

2

ใน Java ตัวดำเนินการเดียว &, |, ^,! ขึ้นอยู่กับตัวถูกดำเนินการ หากตัวถูกดำเนินการทั้งสองเป็น ints การดำเนินการแบบบิตจะดำเนินการ หากทั้งสองเป็นบูลีนจะมีการดำเนินการ "ตรรกะ"

หากตัวถูกดำเนินการทั้งสองไม่ตรงกันข้อผิดพลาดเวลาคอมไพล์จะเกิดขึ้น

ตัวดำเนินการคู่ &&, || ทำงานคล้ายกับคู่ของพวกเขาเดียว แต่ตัวถูกดำเนินการทั้งสองต้องเป็นนิพจน์เงื่อนไขตัวอย่างเช่น:

if ((a <0) && (b <0)) {... } หรือในทำนองเดียวกัน if ((a <0) || (b <0)) {... }

แหล่งที่มา: การเขียนโปรแกรม java lang 4th ed


1

&และ|เป็นตัวดำเนินการระดับบิตในประเภทอินทิกรัล (เช่นint): http://download.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

&&และ||ทำงานกับบูลีนเท่านั้น (และลัดวงจรตามที่คำตอบอื่น ๆ ได้กล่าวไปแล้ว)


3
&และ|ยังเป็นตัวดำเนินการบูลีนในประเภทบูลีน
Marquis of Lorne

1

บางทีอาจเป็นประโยชน์ที่จะทราบว่าตัวดำเนินการบิตและบิตหรือบิตหรือจะได้รับการประเมินก่อนเงื่อนไข AND และเงื่อนไขหรือใช้ในนิพจน์เดียวกันเสมอ

if ( (1>2) && (2>1) | true) // false!

1
คุณหมายถึงลำดับความสำคัญของตัวดำเนินการมากกว่าลำดับการประเมินหรือไม่ ฉันไม่อยากเห็นความแตกต่างของลำดับความสำคัญที่ใช้ในโค้ดจริง ใช้วงเล็บแทนตัวดำเนินการแบบบิตเพื่อจุดประสงค์นี้
John Dvorak

1

&&; || เป็นตัวดำเนินการทางตรรกะ .... ไฟฟ้าลัดวงจร

&; | เป็นตัวดำเนินการทางตรรกะบูลีน .... ไม่ลัดวงจร

ย้ายไปยังความแตกต่างในการดำเนินการกับนิพจน์ ตัวดำเนินการ Bitwise ประเมินทั้งสองด้านโดยไม่คำนึงถึงผลลัพธ์ของด้านซ้ายมือ แต่ในกรณีของการประเมินนิพจน์ด้วยตัวดำเนินการทางตรรกะการประเมินนิพจน์ทางขวามือจะขึ้นอยู่กับเงื่อนไขด้านซ้าย

ตัวอย่างเช่น:

int i = 25;
int j = 25;
if(i++ < 0 && j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

สิ่งนี้จะพิมพ์ i = 26; j = 25 เนื่องจากเงื่อนไขแรกเป็นเท็จเงื่อนไขด้านขวามือจะถูกข้ามเนื่องจากผลลัพธ์เป็นเท็จโดยไม่คำนึงถึงเงื่อนไขด้านขวามือ (ลัดวงจร)

int i = 25;
int j = 25;
if(i++ < 0 & j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

แต่สิ่งนี้จะพิมพ์ i = 26; ญ = 26,


0

หากนิพจน์ที่เกี่ยวข้องกับบูลีน&ตัวดำเนินการได้รับการประเมินตัวถูกดำเนินการทั้งสองจะได้รับการประเมิน จากนั้นตัวดำเนินการ & จะถูกนำไปใช้กับตัวถูกดำเนินการ

เมื่อนิพจน์ที่เกี่ยวข้องกับตัวดำเนินการ&& ได้รับการประเมินตัวถูกดำเนินการแรกจะถูกประเมิน ถ้าตัวถูกดำเนินการแรกประเมินว่าเป็นเท็จการประเมินของตัวถูกดำเนินการที่สองจะถูกข้ามไป

ถ้าตัวถูกดำเนินการตัวแรกส่งคืนค่าเป็นจริงระบบจะประเมินตัวถูกดำเนินการที่สอง ถ้าตัวถูกดำเนินการตัวที่สองส่งคืนค่าเป็นจริงตัวดำเนินการ && จะถูกนำไปใช้กับตัวถูกดำเนินการตัวแรกและตัวที่สอง

คล้ายกับ | และ ||.


0

ในขณะที่ความแตกต่างพื้นฐานคือการที่&จะใช้สำหรับการดำเนินงานส่วนใหญ่ในบิตlong, intหรือที่มันสามารถนำมาใช้สำหรับชนิดของหน้ากากผลลัพธ์อาจแตกต่างกันแม้ว่าคุณจะใช้มันแทนตรรกะbyte&&

ความแตกต่างที่เห็นได้ชัดเจนมากขึ้นในบางสถานการณ์:

  1. การประเมินนิพจน์บางส่วนใช้เวลานาน
  2. การประเมินหนึ่งในนิพจน์สามารถทำได้ก็ต่อเมื่อนิพจน์ก่อนหน้าเป็นจริง
  3. นิพจน์มีผลข้างเคียงบางอย่าง (ตั้งใจหรือไม่)

จุดแรกค่อนข้างตรงไปตรงมาไม่มีจุดบกพร่อง แต่ต้องใช้เวลามากกว่า หากคุณมีการตรวจสอบที่แตกต่างกันหลายรายการในคำสั่งเงื่อนไขเดียวให้วางการตรวจสอบที่มีราคาถูกกว่าหรือมีแนวโน้มที่จะล้มเหลวทางด้านซ้าย

สำหรับจุดที่สองดูตัวอย่างนี้:

if ((a != null) & (a.isEmpty()))

สิ่งนี้ล้มเหลวnullเนื่องจากการประเมินนิพจน์ที่สองจะสร้างไฟล์NullPointerException. ตัวดำเนินการลอจิคัล&&ขี้เกียจถ้าตัวถูกดำเนินการด้านซ้ายเป็นเท็จผลลัพธ์จะเป็นเท็จไม่ว่าตัวถูกดำเนินการด้านขวาจะเป็นอย่างไร

ตัวอย่างสำหรับจุดที่สาม - สมมติว่าเรามีแอปที่ใช้ DB โดยไม่มีทริกเกอร์หรือการเรียงซ้อน ก่อนที่เราจะลบออบเจ็กต์สิ่งปลูกสร้างเราต้องเปลี่ยนสิ่งปลูกสร้างของวัตถุแผนกเป็นอีกสิ่งหนึ่ง สมมติว่าสถานะการดำเนินการจะถูกส่งกลับเป็นบูลีน (true = success) จากนั้น:

if (departmentDao.update(department, newBuilding) & buildingDao.remove(building))

สิ่งนี้จะประเมินนิพจน์ทั้งสองจึงทำการลบสิ่งปลูกสร้างแม้ว่าการอัปเดตแผนกจะล้มเหลวด้วยเหตุผลบางประการ ด้วยการ&&ทำงานตามที่ตั้งใจไว้และหยุดลงหลังจากความล้มเหลวครั้งแรก

สำหรับa || bมันเทียบเท่ากับ!(!a && !b)หยุดถ้าaเป็นจริงไม่จำเป็นต้องอธิบายเพิ่มเติม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.