ทำไมเราถึงใช้ | | มากกว่า | อะไรคือความแตกต่าง?


219

ฉันแค่สงสัยว่าทำไมเรามักจะใช้ตรรกะหรือ||ระหว่างสองบูลีนไม่ได้บิตหรือ|แม้ว่าพวกเขาทั้งสองทำงานได้ดี

ฉันหมายถึงดูที่ต่อไปนี้:

if(true  | true)  // pass
if(true  | false) // pass
if(false | true)  // pass
if(false | false) // no pass
if(true  || true)  // pass
if(true  || false) // pass
if(false || true)  // pass
if(false || false) // no pass

เราสามารถใช้|แทนได้||หรือไม่ สิ่งเดียวกันกับและ&&&


16
คนส่วนใหญ่ลืมไปว่า เป็นตัวดำเนินการบูลีนที่ไม่ลัดวงจรและเป็นตัวดำเนินการระดับบิต
John Meagher

1
รายละเอียดเกี่ยวกับความแตกต่างอยู่ใน JLS ดูjava.sun.com/docs/books/jls/third_edition/html/…
John Meagher

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

4
เพิ่งออกมาจากความอยากรู้อยากเห็นในกรณีใดที่คุณต้องการใช้เวอร์ชันที่ไม่ได้ใช้การลัดวงจร ฉันเกือบจะเคยเห็น&&และแต่ไม่เคย|| & |หากคุณกำลังทำบางสิ่งที่ขึ้นอยู่กับผลข้างเคียงฉันไม่เห็นสาเหตุที่คุณต้องใช้บางสิ่งบางอย่าง(a & b | c)เนื่องจากมีคนคิดได้ง่าย ๆ ว่า "ฉันสามารถเพิ่มประสิทธิภาพสิ่งนี้ได้โดยใช้เวอร์ชันลัดวงจร"
Mike Bailey

2
และแน่นอนว่าพวกเขามีความสำคัญต่างกัน
เลียร้อน

คำตอบ:


349

หากคุณใช้||และ&&รูปแบบแทนที่จะเป็น|และ&รูปแบบของตัวดำเนินการเหล่านี้ Java จะไม่รบกวนการประเมินตัวถูกดำเนินการทางขวาเพียงอย่างเดียว

เป็นเรื่องของถ้าคุณต้องการทำให้การประเมินผลสั้นลงหรือไม่ - ส่วนใหญ่เวลาที่คุณต้องการ

วิธีที่ดีในการอธิบายถึงประโยชน์ของการลัดวงจรคือการพิจารณาตัวอย่างต่อไปนี้

Boolean b = true;
if(b || foo.timeConsumingCall())
{
   //we entered without calling timeConsumingCall()
}

ประโยชน์อีกอย่างที่ Jeremy และ Peter กล่าวถึงสำหรับการลัดวงจรคือการตรวจสอบการอ้างอิงแบบ null:

if(string != null && string.isEmpty())
{
    //we check for string being null before calling isEmpty()
}

ข้อมูลเพิ่มเติม


115
ตัวอย่างที่ยอมรับได้คือfoo != null && foo.hasBar()
Jeremy

1
หากคุณเพิ่มข้อยกเว้นการอ้างอิงค่า null ที่เป็นไปได้โดยใช้ | จากความคิดเห็นของ @ Jeremy นี่เป็นคำตอบที่ดีมาก
Peter Kelly

ยังจำได้ว่า && และ || หมายถึงคำสั่งสาขาที่ระดับรหัสเครื่อง (จำได้ว่าสาขาอาจทำให้เกิดความเข้าใจผิดเกี่ยวกับสาขา) ดังนั้นหากคุณมีความรู้เกี่ยวกับประสิทธิภาพใช้งานได้ก็ต่อเมื่อจำเป็นจริงๆ ( foo != null && foo.hasBar()) หรือเร็วกว่า ( b || foo.timeConsumingCall()) 99% ของนักพัฒนาไม่จำเป็นต้องกังวลเกี่ยวกับการเพิ่มประสิทธิภาพขนาดเล็กระดับนี้
Jonathan Dickinson

3
ฉันประหลาดใจที่ไม่มีใครพูดถึงเมื่อคุณต้องการใช้ | สถานการณ์ที่พบบ่อยที่สุดที่ฉันใช้คือเมื่อตัวแปรถูกแก้ไขในเช็คเช่น (j> 3 | ++ i> 3) หรือ (++ i> 3 | modifiesGlobalAmongOtherThings () = true) ไม่ธรรมดาเหมือนกัน
AndSoYouCode

8
อีกตัวอย่างที่เป็นที่ยอมรับคือstring == null || string.isEmpty();)
Peter Lawrey

83

| ไม่ทำการประเมินการลัดวงจรในนิพจน์บูลีน ||จะหยุดประเมินถ้าตัวถูกดำเนินการแรกเป็นจริง แต่|จะไม่หยุด

นอกจากนี้|ยังสามารถใช้ในการดำเนินการบิต - OR การดำเนินการกับค่าไบต์ / สั้น / int / ยาว ||ไม่ได้.


ให้คำตอบที่สมบูรณ์และฉันจะยอมรับมัน จนถึงตอนนี้คุณเป็นคนแรกที่เลือกแง่มุมนี้
John Meagher

ไม่พบส่วนที่เหมาะสมของ |
John Meagher

63

ดังนั้นเพื่อสร้างคำตอบอื่น ๆ ด้วยตัวอย่างการลัดวงจรเป็นสิ่งสำคัญในการตรวจสอบการป้องกันดังต่อไปนี้:

if (foo == null || foo.isClosed()) {
    return;
}

if (bar != null && bar.isBlue()) {
    foo.doSomething();
}

การใช้|และ&อาจส่งผลให้มีNullPointerExceptionการโยนที่นี่แทน


ถ้าคุณใช้รูปแบบ NullObject มันจะไม่เกิดขึ้น (หรือมากกว่าจะลบล้างคำตอบ) นอกจากนี้ฉันจะบอกว่าตรวจสอบว่า foo เป็นสีฟ้าหรือไม่ ถ้าเป็นสีน้ำเงินแล้วทำอะไรบางอย่างไม่ควรทำอะไรเลย
nicodemus13

@ nicodemus13 - คะแนนดีแม้ว่ารูปแบบของ Null Object นั้นเป็นที่ต้องการในบางครั้งเท่านั้นและร่างกายอาจเป็นสิ่งที่นอกเหนือไปจากการเรียกอีกfooครั้ง "ตัวอย่างมาตรฐาน" ของปีเตอร์ลอว์เรย์เป็นสิ่งที่ดีที่สุด
Paul Bellora

@Khan: ใช่ฉันเป็นคนค่อนข้างลำบากและ Null Object ไม่เหมาะสมเสมอไป ฉันค่อนข้างจะติดนิสัยในการฟื้นฟูสิ่งต่าง ๆ โดยไม่รู้ตัว ไม่มีอะไรผิดปกติกับคำตอบของคุณ
nicodemus13

39

ตรรกะ||และ&&ตรวจสอบทางด้านขวามือหากจำเป็นเท่านั้น |และ&ตรวจสอบทั้งสองด้านทุกครั้ง

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

int i = 12;
if (i == 10 & i < 9) // It will check if i == 10 and if i < 9
...

เขียนมันใหม่:

int i = 12;
if (i == 10 && i < 9) // It will check if i == 10 and stop checking afterward because i != 10
...

ตัวอย่างอื่น:

int i = 12;
if (i == 12 | i > 10) // It will check if i == 12 and it will check if i > 10
...

เขียนมันใหม่:

int i = 12;
if (i == 12 || i > 10) // It will check if i == 12, it does, so it stops checking and executes what is in the if statement
...

18

สังเกตเห็นความผิดพลาดที่พบบ่อยเช่นกัน: ผู้ประกอบการที่ไม่ได้ขี้เกียจมีความสำคัญเหนือกว่าผู้ที่ขี้เกียจดังนั้น:

boolean a, b, c;
a || b && c; //resolves to a || (b && c)
a | b && c; //resolves to (a | b) && c

ระวังเมื่อผสมพวกเขา


15

นอกเหนือจากการลัดวงจรสิ่งอื่นที่ควรทราบคือการใช้การดำเนินการทางตรรกะในระดับบิตที่สามารถเป็นค่าอื่นที่ไม่ใช่ 0 หรือ 1 นั้นมีความหมายแตกต่างจากตรรกะแบบมีเงื่อนไข ในขณะที่มันมักจะเหมือนกันสำหรับ|และ||ด้วย&และ&&คุณจะได้รับผลลัพธ์ที่แตกต่างกันมาก (เช่น2 & 40 / false ในขณะที่2 && 41 / true)

หากสิ่งที่คุณได้รับจากฟังก์ชั่นนั้นเป็นรหัสข้อผิดพลาดจริง ๆ และคุณกำลังทดสอบแบบไม่เป็น 0 นี่อาจมีความสำคัญมาก

นี่ไม่ใช่ปัญหามากใน Java ที่คุณต้องพิมพ์อย่างชัดเจนเพื่อบูลีนหรือเปรียบเทียบกับ 0 หรือสิ่งที่คล้ายกัน แต่ในภาษาอื่นที่มีไวยากรณ์คล้ายกัน (C / C ++ และอื่น ๆ ) อาจทำให้สับสนได้

นอกจากนี้โปรดทราบว่า & และ | สามารถใช้ได้กับค่าจำนวนเต็มเท่านั้นไม่ใช่ทุกอย่างที่เทียบเท่ากับการทดสอบบูลีน อีกครั้งในภาษาที่ไม่ใช่ภาษาจาวามีบางสิ่งที่สามารถใช้เป็นบูลีนที่มีการ!= 0เปรียบเทียบโดยนัย(พอยน์เตอร์, ลอยตัว, วัตถุที่มีoperator bool()ฯลฯ ) และตัวดำเนินการระดับบิตมักจะไร้สาระในบริบทเหล่านั้น


3
ฉันดีใจที่อย่างน้อยบางคนพูดถึงจุดประสงค์ทั้งหมดของการมีอยู่ของผู้ประกอบการระดับบิต
ulidtko

9

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

อย่างไรก็ตามนี่เป็นการเพิ่มประสิทธิภาพแบบไมโครซึ่งไม่ค่อยมีความสำคัญยกเว้นในรหัสระดับต่ำสุด


1
มันจะน่าสนใจว่าคอมไพเลอร์ทำสิ่งนี้โดยอัตโนมัติในบางกรณีหรือไม่
starblue

บางที JIT สามารถทำได้ แต่คอมไพเลอร์มีแนวโน้มที่จะจัดการกับการเพิ่มประสิทธิภาพอย่างง่ายเท่านั้น
Peter Lawrey

2
ใช่ฉันเคยเห็นสถานการณ์ที่ | เร็วกว่าค่าใช้จ่ายสาขาอย่างมาก | | โดยเฉพาะอย่างยิ่งในซีพียูที่ไม่มีการทำนายสาขา มันหายาก แต่ก็ไม่เคยได้ยิน หนึ่งในเพื่อนร่วมงานของฉันเข้าสู่สงครามย้อนกลับในรหัสบางอย่างกับผู้รับเหมาเพราะเขา (ถูกต้อง) โดยใช้ | และผู้รับเหมาก็คิดว่า "ผิด"
ปุย

4
@Fluffy คุณธรรมของเรื่องราวคือถ้าคุณทำอะไรที่ยุ่งยากก็ต้องให้ความเห็นว่าทำไมคุณถึงทำแบบนี้หรือความพยายามของคุณอาจสูญเปล่าในภายหลัง ;)
Peter Lawrey

1
ใช่ในที่สุดเขาก็เพิ่มความคิดเห็น (ตามคำแนะนำของฉันสำหรับวิธีการรับเหมาเพื่อหยุด 'แก้ไข' มัน) และทั้งหมดเป็นอย่างดี
ปุย

8

|| เป็นตรรกะหรือตัวดำเนินการในขณะที่ | คือ bitwise หรือโอเปอเรเตอร์

boolean a = true;
boolean b = false;

if (a || b) {
}

int a = 0x0001;
a = a | 0x0002;

1
พลาดไปที่ | นอกจากนี้ยังเป็นผู้ประกอบการบูลีนไม่ลัดวงจร
John Meagher

2
@ John เกอร์: นั่นเป็นนัยที่เป็นค่าที่เหมาะสม
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

@ L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ คุณสร้างชื่อในสไตล์ที่แตกต่างได้อย่างไร?
UdayKiran Pulipati

8

a | b: ประเมิน b ในกรณีใด ๆ

a | | b: ประเมิน b เฉพาะเมื่อประเมินเป็นเท็จ


7

นอกเหนือจากความจริงที่ว่า | เป็นผู้ประกอบการระดับบิต: || เป็นผู้ดำเนินการลัดวงจร - เมื่อองค์ประกอบหนึ่งเป็นเท็จมันจะไม่ตรวจสอบองค์ประกอบอื่น ๆ

 if(something || someotherthing)
 if(something | someotherthing)

ถ้าบางสิ่งเป็นจริง | | จะไม่ประเมินบางสิ่งขณะที่ | จะทำ. หากตัวแปรในคำสั่ง if ของคุณเป็นฟังก์ชันการโทรจริงให้ใช้ || อาจช่วยประหยัดประสิทธิภาพได้มาก


ทำไมคุณถึงเคยใช้ | ในคำสั่ง if || เป็นบูลีน | ไม่ | จะเป็นบูลีนก็ต่อเมื่อคุณทำงานกับค่าบูลีนสองค่า
FlySwat

นี่เป็นคำตอบแรกที่ได้รับทั้งหมด
John Meagher

คำตอบนี้ไม่ถูกต้อง หากมีสิ่งใดเป็น FALSE ตัวดำเนินการทั้งสองจะไปยังตัวถูกดำเนินการถัดไป ความแตกต่างเกิดขึ้นเฉพาะเมื่อตัวถูกดำเนินการแรกเป็นจริง
Michael Myers

เลวมันมีตัวอย่างที่ไร้สาระอย่างแน่นอน
FlySwat

ฉันไม่รู้ว่าทำไมทุกคนจะใช้ | หรือ & ในคำสั่ง if สำหรับการเปรียบเทียบบูลีนที่เรียบง่าย แต่มันถูกกฎหมายอย่างสมบูรณ์และฉันได้เห็นตัวอย่างจริง ๆ แล้วเมื่อฉันเริ่มเรียนรู้การเขียนโปรแกรม
Michael Stum

3
| is the binary or operator

|| is the logic or operator

2
พลาดไปที่ | นอกจากนี้ยังเป็นผู้ประกอบการบูลีนไม่ลัดวงจร
John Meagher

3

ผู้ประกอบการ||และ&&จะเรียกว่าผู้ประกอบการที่มีเงื่อนไขในขณะที่|และ&จะเรียกว่าค่าที่เหมาะสมประกอบการ พวกเขาตอบสนองวัตถุประสงค์ที่แตกต่าง

ตัวดำเนินการแบบมีเงื่อนไขทำงานเฉพาะกับนิพจน์ที่ประเมินผลแบบคงbooleanที่ทั้งด้านซ้ายและด้านขวา

ตัวดำเนินการ Bitwise ทำงานร่วมกับตัวถูกดำเนินการตัวเลขใด ๆ

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


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

@Hovercraft Full Of Eels: แผนภูมินั้นทำให้เข้าใจผิดเล็กน้อย มันหมายถึงพวกเขาเป็นผู้ประกอบการตามเงื่อนไขเท่านั้นในบริบทของค่าบูลีนที่พวกเขามีทางคณิตศาสตร์เทียบเท่ากับกระตือรือร้นตัวดำเนินการเชิงตรรกะ เมื่อคุณเริ่มจัดการกับสิ่งต่าง ๆ ที่มีค่าอื่นที่ไม่ใช่ 0 หรือ 1 หรือค่าทศนิยมหรือพอยน์เตอร์หรืออะไรก็ตามการเปรียบเทียบจะแยกย่อย
ปุย

@fluffy: ไม่มีสิ่งใดที่ทำให้เข้าใจผิดเกี่ยวกับแผนภูมิเนื่องจากการสนทนาเป็นเรื่องเกี่ยวกับตัวดำเนินการบูลีนเท่านั้น ว่า|และ&สามารถใช้เป็นตัวดำเนินการ bit-wise เป็นปัญหาที่แยกจากกันโดยสิ้นเชิง
Hovercraft ที่เต็มไปด้วยปลาไหล

1
มันจะมีความแม่นยำมากขึ้นในการอ้างถึงพวกเขาเป็นตัวดำเนินการ bit-wise ที่ใช้กับค่าบูลีนและไม่ใช่ตัวดำเนินการบูลีน พวกเขาเพียงแค่เกิดขึ้นเพื่อเทียบเท่าทางคณิตศาสตร์เมื่อมีเพียงบิตเดียว
ปุย

2

หมายเหตุด้านข้าง: Java มี | = แต่ไม่ใช่ || =

ตัวอย่างของเวลาที่คุณต้องใช้ || คือเมื่อการแสดงออกครั้งแรกคือการทดสอบเพื่อดูว่าการแสดงออกที่สองจะระเบิดขึ้น เช่นการใช้ single | ในกรณีต่อไปนี้ของ hte อาจส่งผลให้เกิด NPE

public static boolean isNotSet(String text) {
   return text == null || text.length() == 0;
}

2

คำตอบอื่น ๆ ทำได้ดีมากในการครอบคลุมความแตกต่างของหน้าที่การใช้งานระหว่างตัวดำเนินการ แต่คำตอบสามารถนำไปใช้ได้กับภาษา C ที่ได้จากภาษาเดียวในปัจจุบัน คำถามถูกแท็กด้วยดังนั้นฉันจะพยายามตอบเฉพาะและทางเทคนิคสำหรับภาษาจาวา

&และ|สามารถเป็นผู้ประกอบการ Bitwise อย่างใดอย่างหนึ่งหรือผู้ประกอบการตรรกะบูลีน ไวยากรณ์สำหรับผู้ประกอบการบิตและตรรกะ ( §15.22 ) คือ:

AndExpression:
  EqualityExpression 
  AndExpression & EqualityExpression

ExclusiveOrExpression:
  AndExpression 
  ExclusiveOrExpression ^ AndExpression

InclusiveOrExpression:
  ExclusiveOrExpression 
  InclusiveOrExpression | ExclusiveOrExpression

ไวยากรณ์สำหรับEqualityExpressionถูกกำหนดใน§15.21ซึ่งต้องการRelationalExpressionกำหนดไว้ใน§15.20ซึ่งจำเป็นต้องมีShiftExpressionและReferenceTypeกำหนดไว้ใน§15.19และ§4.3ตามลำดับ ShiftExpressionต้องAdditiveExpressionกำหนดไว้ใน§15.18ซึ่งยังคงเจาะลึกการกำหนดเลขคณิตพื้นฐานผู้ประกอบการเอกและอื่น ๆReferenceTypeเจาะลึกลงไปในทุกวิธีที่จะเป็นตัวแทนของประเภท (ในขณะที่ReferenceTypeไม่รวมถึงรูปแบบดั้งเดิมความหมายของรูปแบบดั้งเดิมจะต้องที่สุดเท่าที่พวกเขาอาจจะเป็นประเภทมิติสำหรับอาร์เรย์ซึ่งเป็นReferenceType .)

ตัวดำเนินการบิตและตรรกะมีคุณสมบัติดังต่อไปนี้:

  • ตัวดำเนินการเหล่านี้มีลำดับความสำคัญต่างกันโดย&มีลำดับความสำคัญสูงสุดและ|ลำดับความสำคัญต่ำสุด
  • ผู้ประกอบการเหล่านี้แต่ละรายมีความสัมพันธ์ทางซ้าย (แต่ละกลุ่มจากซ้ายไปขวา)
  • ตัวดำเนินการแต่ละตัวเป็นแบบสับเปลี่ยนถ้านิพจน์ตัวถูกดำเนินการไม่มีผลข้างเคียง
  • ผู้ประกอบการแต่ละคนมีความสัมพันธ์
  • booleanค่าบิตและตรรกะผู้ประกอบการอาจถูกใช้เพื่อเปรียบเทียบสองตัวถูกดำเนินการประเภทที่เป็นตัวเลขหรือสองตัวถูกดำเนินการประเภท กรณีอื่นทั้งหมดทำให้เกิดข้อผิดพลาดในการคอมไพล์

ความแตกต่างระหว่างไม่ว่าจะเป็นผู้ประกอบการที่ทำหน้าที่เป็นผู้ประกอบการระดับบิตหรือผู้ประกอบการเชิงตรรกะขึ้นอยู่กับว่าตัวถูกดำเนินการเป็น "แปลงสภาพให้แก่ชนิดหนึ่งดั้งเดิม" ( §4.2 ) หรือถ้าพวกเขาเป็นประเภทbooleanหรือBoolean( §5.1.8 )

หากตัวถูกดำเนินการเป็นประเภทที่สมบูรณ์การส่งเสริมตัวเลขไบนารี ( §5.6.2 ) จะดำเนินการกับตัวถูกดำเนินการทั้งสองโดยปล่อยให้ตัวถูกดำเนินการทั้งสองเป็นlongs หรือints สำหรับการดำเนินการ ประเภทของการดำเนินการจะเป็นประเภทของตัวถูกดำเนินการ (เลื่อนระดับ) ณ จุดนั้น&จะเป็นระดับบิตและ^จะเป็นระดับบิตพิเศษและ|จะรวมระดับบิต ( §15.22.1 )

ถ้าตัวถูกดำเนินการที่มีbooleanหรือBoolean, ตัวถูกดำเนินการจะต้องมีการแปลง unboxing หากจำเป็น ( §5.1.8 ) booleanและประเภทของการดำเนินการจะเป็น &จะส่งผลให้trueถ้าทั้งสองตัวถูกดำเนินการอยู่true, ^จะส่งผลให้trueถ้าทั้งสองตัวถูกดำเนินการที่แตกต่างกันและ|จะมีผลในกรณีใดกรณีหนึ่งถูกดำเนินการคือtrue true( §15.22.2 )

ในทางตรงกันข้าม &&คือ "เงื่อนไข - และผู้ดำเนินการ" ( §15.23 ) และ||เป็น "ผู้ประกอบการตามเงื่อนไข" ( §15.24 ) ไวยากรณ์ของพวกเขาถูกกำหนดเป็น:

ConditionalAndExpression:
  InclusiveOrExpression 
  ConditionalAndExpression && InclusiveOrExpression

ConditionalOrExpression:
  ConditionalAndExpression 
  ConditionalOrExpression || ConditionalAndExpression

&&เป็นเหมือนยกเว้นว่ามันจะประเมินเฉพาะตัวถูกดำเนินการที่เหมาะสมถ้าถูกดำเนินการทางด้านซ้ายคือ& เป็นเหมือนยกเว้นว่ามันจะประเมินเฉพาะตัวถูกดำเนินการที่เหมาะสมถ้าถูกดำเนินการทางด้านซ้ายคือtrue|||false

เงื่อนไข - และมีคุณสมบัติดังต่อไปนี้:

  • เงื่อนไขและโอเปอเรเตอร์ถูกเชื่อมโยงทางซ้าย (สัมพันธ์กันจากซ้ายไปขวา)
  • เงื่อนไขและโอเปอเรเตอร์นั้นสัมพันธ์กันอย่างสมบูรณ์เกี่ยวกับผลข้างเคียงและค่าผลลัพธ์ นั่นคือสำหรับการแสดงออกใด ๆa, bและcการประเมินผลของการแสดงออกผลิตผลเดียวกันกับผลข้างเคียงที่เกิดขึ้นในการสั่งซื้อเช่นเดียวกับการประเมินผลของการแสดงออก((a) && (b)) && (c)(a) && ((b) && (c))
  • ตัวถูกดำเนินการแต่ละรายการของเงื่อนไขและตัวดำเนินการต้องเป็นประเภทbooleanหรือBooleanหรือเกิดข้อผิดพลาดในการรวบรวมเวลา
  • booleanประเภทของเงื่อนไขและการแสดงออกอยู่เสมอ
  • ณ รันไทม์นิพจน์ตัวถูกดำเนินการทางซ้ายจะถูกประเมินก่อน หากผลลัพธ์มีประเภทBooleanนั้นจะขึ้นอยู่กับการยกเลิกการแปลงกล่อง ( §5.1.8 )
  • หากค่าผลลัพธ์คือfalseค่าของเงื่อนไขและนิพจน์คือfalseและนิพจน์ตัวถูกดำเนินการทางด้านขวาจะไม่ถูกประเมิน
  • หากค่าของตัวถูกดำเนินtrueการทางซ้ายคือแสดงการแสดงออกทางขวามือ; หากผลลัพธ์มีประเภทBooleanนั้นจะขึ้นอยู่กับการยกเลิกการแปลงกล่อง ( §5.1.8 ) ค่าผลลัพธ์จะกลายเป็นค่าของเงื่อนไขและนิพจน์
  • ดังนั้น&&คำนวณผลลัพธ์เช่นเดียว&กับในbooleanตัวถูกดำเนินการ มันแตกต่างกันเฉพาะในการแสดงออกของตัวถูกดำเนินการทางขวาจะถูกประเมินตามเงื่อนไขมากกว่าเสมอ

เงื่อนไข - หรือมีคุณสมบัติดังต่อไปนี้:

  • เงื่อนไขหรือโอเปอเรเตอร์มีการเชื่อมโยงจากด้านซ้ายของไวยากรณ์ (จัดกลุ่มจากซ้ายไปขวา)
  • เงื่อนไขหรือตัวดำเนินการสัมพันธ์อย่างเต็มที่กับทั้งผลข้างเคียงและค่าผลลัพธ์ นั่นคือสำหรับการแสดงออกใด ๆa, bและcการประเมินผลของการแสดงออกผลิตผลเดียวกันกับผลข้างเคียงที่เกิดขึ้นในการสั่งซื้อเช่นเดียวกับการประเมินผลของการแสดงออก((a) || (b)) || (c)(a) || ((b) || (c))
  • ตัวถูกดำเนินการแต่ละรายการของเงื่อนไขหรือตัวดำเนินการต้องเป็นประเภทbooleanหรือBooleanหรือเกิดข้อผิดพลาดในการรวบรวม
  • booleanประเภทของเงื่อนไขหรือการแสดงออกอยู่เสมอ
  • ณ รันไทม์นิพจน์ตัวถูกดำเนินการทางซ้ายจะถูกประเมินก่อน หากผลลัพธ์มีประเภทBooleanนั้นจะขึ้นอยู่กับการยกเลิกการแปลงกล่อง ( §5.1.8 )
  • หากค่าผลลัพธ์คือtrueค่าของเงื่อนไขหรือนิพจน์คือtrueและนิพจน์ตัวถูกดำเนินการทางขวานั้นไม่ได้รับการประเมิน
  • หากค่าของตัวถูกดำเนินfalseการทางซ้ายคือแสดงการแสดงออกทางขวามือ; หากผลลัพธ์มีประเภทBooleanนั้นจะขึ้นอยู่กับการยกเลิกการแปลงกล่อง ( §5.1.8 ) ค่าผลลัพธ์จะกลายเป็นค่าของเงื่อนไขหรือนิพจน์
  • ดังนั้น||คำนวณผลลัพธ์เช่นเดียว|กับในbooleanหรือBooleanถูกดำเนินการ มันแตกต่างกันเฉพาะในการแสดงออกของตัวถูกดำเนินการทางขวาจะถูกประเมินตามเงื่อนไขมากกว่าเสมอ

ในระยะสั้นเป็น @JohnMeagher ได้ชี้ให้เห็นซ้ำ ๆ ออกมาในความคิดเห็น&และ|ในความเป็นจริงไม่ใช่ลัดวงจรประกอบการบูลีนในกรณีที่เฉพาะเจาะจงของตัวถูกดำเนินการเป็นอย่างใดอย่างหนึ่งหรือboolean Booleanด้วยแนวทางปฏิบัติที่ดี (เช่น: ไม่มีผลรอง) นี่เป็นความแตกต่างเล็กน้อย เมื่อตัวถูกดำเนินการไม่ใช่booleans หรือBooleans ตัวดำเนินการจะทำงานแตกต่างกันมาก : บิตและการดำเนินการแบบลอจิคัลนั้นไม่สามารถเปรียบเทียบได้ดีกับการเขียนโปรแกรมจาวาระดับสูง


2

1). (expression1 | expression2), | โอเปอเรเตอร์จะประเมิน expression2 โดยไม่คำนึงว่าผลลัพธ์ของ expression1 เป็นจริงหรือเท็จ

ตัวอย่าง:

class Or 
{
    public static void main(String[] args) 
    {
        boolean b=true;

        if (b | test());
    }

    static boolean test()
    {
        System.out.println("No short circuit!");
        return false;
    }
}

2). (expression1 || expression2), || ผู้ประกอบการจะไม่ประเมิน expression2 ถ้า expression1 เป็นจริง

ตัวอย่าง:

class Or 
{
    public static void main(String[] args) 
    {
        boolean b=true;

        if (b || test())
        {
            System.out.println("short circuit!");
        }
    }

    static boolean test()
    {
        System.out.println("No short circuit!");
        return false;
    }
}

1

|| ส่งคืนค่าบูลีนโดย OR'ing สองค่า (นั่นคือสาเหตุที่รู้จักกันในชื่อตรรกะหรือ)

IE:

if (A || B) 

จะกลับมาจริงถ้าทั้ง A หรือ B เป็นจริงหรือเท็จถ้าพวกเขาทั้งสองเป็นเท็จ

| เป็นตัวดำเนินการที่ดำเนินการกับค่าสองค่าในระดับบิต เพื่อให้เข้าใจการทำงานระดับบิตได้ดีขึ้นคุณสามารถอ่านได้ที่นี่:

http://en.wikipedia.org/wiki/Bitwise_operation


1

ความแตกต่างหลักอย่างหนึ่งคือ | | และ && แสดง "การลัดวงจร" ดังนั้น RHS จะได้รับการประเมินถ้าจำเป็นเท่านั้น

สำหรับเช่น

if (a || b) {
    path1...
} else {
    path2..
}

ด้านบนถ้า a เป็นจริง b จะไม่ถูกทดสอบและดำเนินการ path1 ถ้า | ถูกใช้แล้วทั้งสองฝ่ายจะได้รับการประเมินแม้ว่า 'a' จะเป็นจริง

ดูที่นี่และที่นี่สำหรับข้อมูลเพิ่มเติมเล็กน้อย

หวังว่านี่จะช่วยได้


1

การลัดวงจรที่ไม่มีประโยชน์อาจมีประโยชน์ บางครั้งคุณต้องการแน่ใจว่านิพจน์ทั้งสองนั้นประเมิน ตัวอย่างเช่นสมมติว่าคุณมีวิธีที่ลบวัตถุออกจากรายการสองรายการที่แยกกัน คุณอาจต้องการทำสิ่งนี้:

class foo {

    ArrayList<Bar> list1 = new ArrayList<Bar>();
    ArrayList<Bar> list2 = new ArrayList<Bar>();

    //Returns true if bar is removed from both lists, otherwise false.
    boolean removeBar(Bar bar) {
        return (list1.remove(bar) & list2.remove(bar));
    }
}

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

//Fails to execute the second remove if the first returns false.
boolean removeBar(Bar bar) {
    return (list1.remove(bar) && list2.remove(bar));
}

มันไม่มีประโยชน์อย่างน่าอัศจรรย์และ (เช่นเดียวกับงานด้านการเขียนโปรแกรมส่วนใหญ่) คุณสามารถทำให้สำเร็จด้วยวิธีการอื่น แต่มันเป็นกรณีการใช้งานสำหรับตัวถูกดำเนินการระดับบิต


1

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

int two = -2; int four = -4;
result = two | four; // bitwise OR example

System.out.println(Integer.toBinaryString(two));
System.out.println(Integer.toBinaryString(four));
System.out.println(Integer.toBinaryString(result));

Output:
11111111111111111111111111111110
11111111111111111111111111111100
11111111111111111111111111111110

อ่านเพิ่มเติม: http://javarevisited.blogspot.com/2015/01/difference-between-bitwsie-and-logical.html#ixzz45PCxdQhk


ไม่จริงเมื่อตัวถูกดำเนินการเป็น booleans และการจัดรูปแบบโง่
มาร์ควิสแห่ง Lorne

2
สิ่งนี้มีประโยชน์สำหรับฉันในการทำความเข้าใจว่าทำไม Long.valueOf (100 | 200) = 236 นี่คือเหตุผล: 0 1 1 0 0 1 1 0 0 | 1 1 0 0 1 0 0 0 = 1 1 1 0 1 1 0 0 = 128 64 32 0 8 4 0 0 = 236
donlys

1

เมื่อฉันมีคำถามนี้ฉันสร้างรหัสทดสอบเพื่อรับแนวคิดเกี่ยวกับเรื่องนี้

public class HelloWorld{

   public static boolean bool(){
      System.out.println("Bool");
      return true;
   }

   public static void main(String []args){

     boolean a = true;
     boolean b = false;

     if(a||bool())
     {
        System.out.println("If condition executed"); 
     }
     else{
         System.out.println("Else condition executed");
     }

 }
}

ในกรณีนี้เราเพียงเปลี่ยนค่าด้านซ้ายของถ้าเงื่อนไขเพิ่ม a หรือ b

|| สถานการณ์สมมติเมื่อด้านซ้ายเป็นจริง [if (a || bool ())]

เอาท์พุต "If condition executed"

|| สถานการณ์สมมติเมื่อด้านซ้ายเป็นเท็จ [if (b || bool ())]

Output-

Bool
If condition executed

Conclusion of || เมื่อใช้งาน||ทางด้านขวาจะตรวจสอบเมื่อด้านซ้ายเป็นเท็จเท่านั้น

| สถานการณ์สมมติเมื่อด้านซ้ายเป็นจริง [ถ้า (a | bool ())]

Output-

Bool
If condition executed

| สถานการณ์สมมติเมื่อด้านซ้ายเป็นเท็จ [ถ้า (b | bool ())]

Output-

Bool
If condition executed

Conclusion of | เมื่อใช้งาน|ให้ตรวจสอบทั้งด้านซ้ายและด้านขวา


0

| = bitwise หรือ, || ตรรกะหรือ


2
พลาดไปที่ | นอกจากนี้ยังเป็นผู้ประกอบการบูลีนไม่ลัดวงจร
John Meagher

0

ฉันมักจะใช้เมื่อมีการเพิ่มขึ้นก่อนและผู้ประกอบการเพิ่มโพสต์ ดูรหัสต่อไปนี้:

package ocjpPractice;
/**
 * @author tithik
 *
 */
public class Ex1 {

    public static void main(String[] args) {
    int i=10;
    int j=9;
    int x=10;
    int y=9;
    if(i==10 | ++i>j){
        System.out.println("it will print in first if");  
        System.out.println("i is: "+i);
    }

    if(x==10 ||++x>y){
        System.out.println("it will print in second if");   
        System.out.println("x is: "+x);
    }
    }
}

เอาท์พุท:

มันจะพิมพ์ก่อนถ้า
ฉันคือ: 11

มันจะพิมพ์ครั้งที่สองถ้า
x คือ: 10

ifบล็อกทั้งสองเหมือนกัน แต่ผลลัพธ์ต่างกัน เมื่อมี|เงื่อนไขทั้งสองจะได้รับการประเมิน แต่ถ้าเป็น||เช่นนั้นจะไม่ประเมินเงื่อนไขที่สองเนื่องจากเงื่อนไขแรกเป็นจริงอยู่แล้ว


1
ฉันพบว่ามันสับสนมาก
NimChimpsky

0

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

ตัวอย่างเช่นหากคุณต้องการตรวจสอบความถูกต้องของแบบฟอร์มและคุณต้องการให้ผู้ใช้เห็นฟิลด์ที่ไม่ถูกต้องทั้งหมดพร้อมข้อความข้อผิดพลาดแทนที่จะเป็นเพียงฟิลด์แรกที่ไม่ถูกต้อง

|| ผู้ประกอบการจะเป็น

   if(checkIfEmpty(nameField) || checkIfEmpty(phoneField) || checkIfEmpty(emailField)) {
      // invalid form with one or more empty fields
   }

   private boolean checkIfEmpty(Widget field) {
      if(field.isEmpty()) {
        field.setErrorMessage("Should not be empty!");
        return true;
      }
      return false;
   }

ดังนั้นด้วยตัวอย่างข้างต้นหากผู้ใช้ส่งแบบฟอร์มพร้อมฟิลด์ว่างทั้งหมดnameFieldจะปรากฏพร้อมข้อความแสดงข้อผิดพลาดเท่านั้น แต่ถ้าคุณเปลี่ยนเป็น

   if(checkIfEmpty(nameField) | checkIfEmpty(phoneField) | checkIfEmpty(emailField)) {
      // invalid form with one or more empty fields
   }

มันจะแสดงข้อความผิดพลาดที่เหมาะสมในแต่ละฟิลด์โดยไม่คำนึงถึงtrueเงื่อนไข


0

หลังจากอ่านหัวข้อนี้อย่างถี่ถ้วนแล้วยังคงไม่ชัดเจนสำหรับฉันหากใช้|เป็นตัวดำเนินการเชิงตรรกะสอดคล้องกับรูปแบบ Java

ฉันเพิ่งแก้ไขรหัสในคำขอดึงที่อยู่ความคิดเห็นที่

if(function1() | function2()){
  ...
}

ต้องเปลี่ยนเป็น

boolean isChanged = function1();
isChanged |= function2();
if (isChanged){
  ...
}

รุ่นที่ยอมรับจริงคืออะไร

เอกสารประกอบของ Java ไม่ได้กล่าวถึง|ว่าเป็นตัวดำเนินการ OR ที่ไม่ใช่การลัดวงจรแบบตรรกะ

ไม่สนใจในการลงคะแนน แต่เพิ่มเติมในการหามาตรฐาน?! รหัสทั้งสองรุ่นรวบรวมและทำงานตามที่คาดไว้





-2

| เป็นผู้ประกอบการระดับบิต || เป็นตัวดำเนินการเชิงตรรกะ

หนึ่งจะใช้เวลาสองบิตและหรือพวกเขา

หนึ่งจะกำหนดความจริง (นี้หรือที่) หากเป็นจริงหรือที่เป็นจริงแล้วคำตอบนั้นเป็นจริง

โอ้แล้วคนก็ตอบคำถามเหล่านี้อย่างรวดเร็ว

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