ฉันรู้กฎสำหรับ&&
และ||
แต่อะไรคืออะไร&
และ|
? โปรดอธิบายสิ่งเหล่านี้ให้ฉันฟังด้วยตัวอย่าง
ฉันรู้กฎสำหรับ&&
และ||
แต่อะไรคืออะไร&
และ|
? โปรดอธิบายสิ่งเหล่านี้ให้ฉันฟังด้วยตัวอย่าง
คำตอบ:
สิ่งเหล่านี้คือตัวดำเนินการ 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
ค่าจริงโดยเพิ่มข้อยกเว้น
ฉันคิดว่าคุณกำลังพูดถึงความหมายเชิงตรรกะของตัวดำเนินการทั้งสองที่นี่คุณมีตารางประวัติย่อ:
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 โดยยกข้อยกเว้น
ฉันรู้ว่ามีคำตอบมากมายที่นี่ แต่พวกเขาทั้งหมดดูสับสนเล็กน้อย ดังนั้นหลังจากทำการค้นคว้าจากคู่มือการศึกษา 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
สิ่งที่คุณอธิบายนั้นถูกต้อง แต่เหตุผลที่คุณระบุไม่เป็นเช่นนั้นสำหรับฉันอย่างน้อย ..
ตัวดำเนินการ && และ || เป็นการลัดวงจรซึ่งหมายความว่าพวกเขาจะไม่ประเมินนิพจน์ทางขวามือหากค่าของนิพจน์ทางซ้ายเพียงพอที่จะกำหนดผลลัพธ์
& และ | ให้ผลลัพธ์เช่นเดียวกับ && และ || ตัวดำเนินการ ความแตกต่างคือพวกเขามักจะประเมินทั้งสองด้านของนิพจน์โดยที่ && และ || หยุดประเมินว่าเงื่อนไขแรกเพียงพอที่จะตัดสินผลลัพธ์หรือไม่
&&
มันจะประเมินผลลัพธ์ทั้งสองในขณะที่||
ส่งกลับก็ต่อเมื่อเงื่อนไขแรกเป็นจริง
( 2 & 4 )
ประเมินfalse
ในขณะที่ประเมิน( 2 && 4 )
true
ผลลัพธ์เดียวกันนั้นเป็นอย่างไร?
2 & 4
ผลลัพธ์เป็นจำนวนเต็มไม่ใช่บูลีน (ศูนย์ในกรณีนี้) 2 && 4
จะไม่คอมไพล์ && ยอมรับเฉพาะบูลีน Java ไม่อนุญาตให้ผสม booleans และ ints: ศูนย์ไม่ได้false
, false
ไม่เป็นศูนย์ ...
&&
true
ใน Java ตัวดำเนินการเดียว &, |, ^,! ขึ้นอยู่กับตัวถูกดำเนินการ หากตัวถูกดำเนินการทั้งสองเป็น ints การดำเนินการแบบบิตจะดำเนินการ หากทั้งสองเป็นบูลีนจะมีการดำเนินการ "ตรรกะ"
หากตัวถูกดำเนินการทั้งสองไม่ตรงกันข้อผิดพลาดเวลาคอมไพล์จะเกิดขึ้น
ตัวดำเนินการคู่ &&, || ทำงานคล้ายกับคู่ของพวกเขาเดียว แต่ตัวถูกดำเนินการทั้งสองต้องเป็นนิพจน์เงื่อนไขตัวอย่างเช่น:
if ((a <0) && (b <0)) {... } หรือในทำนองเดียวกัน if ((a <0) || (b <0)) {... }
แหล่งที่มา: การเขียนโปรแกรม java lang 4th ed
&
และ|
เป็นตัวดำเนินการระดับบิตในประเภทอินทิกรัล (เช่นint
): http://download.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
&&
และ||
ทำงานกับบูลีนเท่านั้น (และลัดวงจรตามที่คำตอบอื่น ๆ ได้กล่าวไปแล้ว)
&
และ|
ยังเป็นตัวดำเนินการบูลีนในประเภทบูลีน
บางทีอาจเป็นประโยชน์ที่จะทราบว่าตัวดำเนินการบิตและบิตหรือบิตหรือจะได้รับการประเมินก่อนเงื่อนไข AND และเงื่อนไขหรือใช้ในนิพจน์เดียวกันเสมอ
if ( (1>2) && (2>1) | true) // false!
&&; || เป็นตัวดำเนินการทางตรรกะ .... ไฟฟ้าลัดวงจร
&; | เป็นตัวดำเนินการทางตรรกะบูลีน .... ไม่ลัดวงจร
ย้ายไปยังความแตกต่างในการดำเนินการกับนิพจน์ ตัวดำเนินการ 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,
หากนิพจน์ที่เกี่ยวข้องกับบูลีน&ตัวดำเนินการได้รับการประเมินตัวถูกดำเนินการทั้งสองจะได้รับการประเมิน จากนั้นตัวดำเนินการ & จะถูกนำไปใช้กับตัวถูกดำเนินการ
เมื่อนิพจน์ที่เกี่ยวข้องกับตัวดำเนินการ&& ได้รับการประเมินตัวถูกดำเนินการแรกจะถูกประเมิน ถ้าตัวถูกดำเนินการแรกประเมินว่าเป็นเท็จการประเมินของตัวถูกดำเนินการที่สองจะถูกข้ามไป
ถ้าตัวถูกดำเนินการตัวแรกส่งคืนค่าเป็นจริงระบบจะประเมินตัวถูกดำเนินการที่สอง ถ้าตัวถูกดำเนินการตัวที่สองส่งคืนค่าเป็นจริงตัวดำเนินการ && จะถูกนำไปใช้กับตัวถูกดำเนินการตัวแรกและตัวที่สอง
คล้ายกับ | และ ||.
ในขณะที่ความแตกต่างพื้นฐานคือการที่&
จะใช้สำหรับการดำเนินงานส่วนใหญ่ในบิตlong
, int
หรือที่มันสามารถนำมาใช้สำหรับชนิดของหน้ากากผลลัพธ์อาจแตกต่างกันแม้ว่าคุณจะใช้มันแทนตรรกะbyte
&&
ความแตกต่างที่เห็นได้ชัดเจนมากขึ้นในบางสถานการณ์:
จุดแรกค่อนข้างตรงไปตรงมาไม่มีจุดบกพร่อง แต่ต้องใช้เวลามากกว่า หากคุณมีการตรวจสอบที่แตกต่างกันหลายรายการในคำสั่งเงื่อนไขเดียวให้วางการตรวจสอบที่มีราคาถูกกว่าหรือมีแนวโน้มที่จะล้มเหลวทางด้านซ้าย
สำหรับจุดที่สองดูตัวอย่างนี้:
if ((a != null) & (a.isEmpty()))
สิ่งนี้ล้มเหลวnull
เนื่องจากการประเมินนิพจน์ที่สองจะสร้างไฟล์NullPointerException
. ตัวดำเนินการลอจิคัล&&
ขี้เกียจถ้าตัวถูกดำเนินการด้านซ้ายเป็นเท็จผลลัพธ์จะเป็นเท็จไม่ว่าตัวถูกดำเนินการด้านขวาจะเป็นอย่างไร
ตัวอย่างสำหรับจุดที่สาม - สมมติว่าเรามีแอปที่ใช้ DB โดยไม่มีทริกเกอร์หรือการเรียงซ้อน ก่อนที่เราจะลบออบเจ็กต์สิ่งปลูกสร้างเราต้องเปลี่ยนสิ่งปลูกสร้างของวัตถุแผนกเป็นอีกสิ่งหนึ่ง สมมติว่าสถานะการดำเนินการจะถูกส่งกลับเป็นบูลีน (true = success) จากนั้น:
if (departmentDao.update(department, newBuilding) & buildingDao.remove(building))
สิ่งนี้จะประเมินนิพจน์ทั้งสองจึงทำการลบสิ่งปลูกสร้างแม้ว่าการอัปเดตแผนกจะล้มเหลวด้วยเหตุผลบางประการ ด้วยการ&&
ทำงานตามที่ตั้งใจไว้และหยุดลงหลังจากความล้มเหลวครั้งแรก
สำหรับa || b
มันเทียบเท่ากับ!(!a && !b)
หยุดถ้าa
เป็นจริงไม่จำเป็นต้องอธิบายเพิ่มเติม