เปรียบเทียบสมาชิก Java enum: == หรือเท่ากับ ()?


1736

ฉันรู้ว่า Java enums ถูกคอมไพล์ไปยังคลาสที่มีคอนสตรัคเตอร์ส่วนตัวและสมาชิกสแตติกสาธารณะ เมื่อเปรียบเทียบสมาชิกสองคนของ enum ที่กำหนดฉันใช้เสมอ.equals()เช่น

public useEnums(SomeEnum a)
{
    if(a.equals(SomeEnum.SOME_ENUM_VALUE))
    {
        ...
    }
    ...
}

อย่างไรก็ตามฉันเพิ่งเจอรหัสบางส่วนที่ใช้ตัวดำเนินการเท่ากับ==แทน. equals ():

public useEnums2(SomeEnum a)
{
    if(a == SomeEnum.SOME_ENUM_VALUE)
    {
        ...
    }
    ...
}

ฉันควรใช้โอเปอเรเตอร์แบบใด


7
ฉันเพิ่งพบคำถามที่คล้ายกันมาก: stackoverflow.com/questions/533922/ …
Matt Ball

39
ฉันประหลาดใจที่ในคำตอบทั้งหมด (โดยเฉพาะอย่างยิ่งจาก polygenelubricants ซึ่งอธิบายในรายละเอียดว่าทำไม == ทำงาน) ที่ไม่ได้กล่าวถึงประโยชน์ที่ยิ่งใหญ่อีกอย่างของ ==: มันทำให้ชัดเจนว่า enums ทำงานอย่างไร (เป็นชุดคงที่ของซิงเกิล วัตถุ) ด้วยเท่ากับมันนำไปสู่การคิดว่ามีอย่างใดอย่างหนึ่งอาจมีหลายกรณีของ 'ทางเลือก' Enum เดียวกันลอยไปรอบ ๆ
Stuart Rossiter

6
ง่าย ๆ เข้าไว้. "==" สามารถอ่านได้มากขึ้นและใช้งานได้เนื่องจาก enums เป็นซิงเกิลโดยค่าเริ่มต้น Ref
lokesh

คำตอบ:


1576

ทั้งสองถูกต้องทางเทคนิค ถ้าคุณดูซอร์สโค้ด.equals()มันก็จะ==เปลี่ยนไป

ฉันใช้==อย่างไรก็ตามเนื่องจากจะปลอดภัย


64
โดยส่วนตัวแล้วฉันไม่ชอบ 'null safety' ที่กล่าวถึงเป็นเหตุผลในการใช้ ==
Nivas

257
@Nivas: ทำไมไม่ คุณชอบที่จะกังวลเกี่ยวกับลำดับการโต้แย้งของคุณ (ซึ่งจะใช้กับการเปรียบเทียบค่าคงที่จากทางซ้ายเช่นเดียวกับในคำตอบของ Pascal)? คุณชอบที่จะตรวจสอบเสมอว่าค่าไม่เป็นโมฆะก่อน.equals()นำเข้าหรือไม่ ฉันรู้ว่าฉันทำไม่ได้
Matt Ball

86
โปรดทราบว่าเมื่ออ่านรหัสของคุณ "==" อาจปรากฏขึ้นไม่ถูกต้องกับผู้อ่านจนกว่าเขา / เธอจะออกไปและดูที่แหล่งที่มาของประเภทที่เกี่ยวข้องจากนั้นเห็นว่าเป็น enum ในแง่นั้นมันเสียสมาธิน้อยกว่าในการอ่าน ".equals ()"
Kevin Bourrillion

60
@Kevin - หากคุณไม่ได้ใช้ IDE ที่ให้คุณเห็นประเภทโดยตรงเมื่อดูแหล่งที่มาคุณกำลังนอกใจตัวเอง - ไม่ใช่ปัญหากับ IDE ที่เหมาะสม
MetroidFan2002

63
บางครั้งโค้ดจะถูก refactored และเป็นไปได้ที่ enum จะถูกแทนที่ด้วยคลาส ณ จุด == ไม่รับประกันว่าจะถูกต้องอีกต่อไปในขณะที่ค่าเท่ากับยังคงทำงานได้อย่างราบรื่น ด้วยเหตุผลนี้เท่ากับเป็นตัวเลือกที่ดีกว่าอย่างชัดเจน ถ้าคุณต้องการความปลอดภัยเป็นโมฆะ (เพราะคุณทำงานบนฐานของรหัสที่ไม่ได้เขียนเพื่อลดการใช้โมฆะ) มี Apache ObjectUtils หรือ Guava's Objects # เท่ากับ (หรือคุณสามารถหมุนของคุณเอง) ฉันจะไม่พูดถึงคำว่า "การแสดง" เพราะกลัวว่าจะมีใครตบฉันอย่างถูกต้องด้วยหนังสือโดนัลด์นัทท์
laszlok

1113

สามารถ==ใช้กับenum?

ใช่: enums มีการควบคุมอินสแตนซ์ที่ จำกัด ที่ช่วยให้คุณใช้==เพื่อเปรียบเทียบอินสแตนซ์ นี่คือการรับประกันโดยข้อกำหนดภาษา (เน้นโดยฉัน):

JLS 8.9 Enums

ประเภท enum ไม่มีอินสแตนซ์อื่นนอกเหนือจากที่กำหนดโดยค่าคงที่ enum

มันเป็นข้อผิดพลาดในการคอมไพล์เวลาพยายามที่จะยกตัวอย่างอย่างชัดเจนประเภท enum final cloneวิธีในการEnumทำให้มั่นใจว่าenumคงไม่สามารถโคลนและการดูแลเป็นพิเศษโดยมั่นใจกลไกอนุกรมว่ากรณีที่ซ้ำกันจะไม่เคยสร้างเป็นผลมาจาก deserialization ห้ามมิให้มีการสะท้อนกลับของชนิด enum ร่วมกันสิ่งทั้งสี่นี้ช่วยให้แน่ใจว่าไม่มีอินสแตนซ์ของenumประเภทที่เกินกว่าที่กำหนดโดยenumค่าคงที่

เนื่องจากมีเพียงหนึ่งตัวอย่างของแต่ละenumคงได้รับอนุญาตให้ใช้==ประกอบการในสถานที่ของequalsวิธีการเมื่อเปรียบเทียบสองอ้างอิงวัตถุถ้ามันเป็นที่รู้จักกันว่าอย่างน้อยหนึ่งของพวกเขาหมายถึงenumอย่างต่อเนื่อง ( equalsวิธีการในEnumเป็นfinalวิธีการที่เรียกใช้super.equalsการโต้แย้งและส่งคืนผลลัพธ์เท่านั้นจึงทำการเปรียบเทียบตัวตน)

การรับประกันนี้มีความแข็งแกร่งเพียงพอที่ Josh Bloch แนะนำว่าหากคุณยืนยันในการใช้รูปแบบซิงเกิลวิธีที่ดีที่สุดในการติดตั้งคือการใช้องค์ประกอบเดียวenum(ดู: มีผลบังคับใช้ Java 2nd Edition รายการ 3: บังคับใช้คุณสมบัติ Singleton ด้วย คอนสตรัคส่วนตัวหรือประเภท enum ; และยังปลอดภัยเรื่องเธรดในซิงเกิล )


อะไรคือความแตกต่างระหว่าง==และequals?

เพื่อเป็นการเตือนความจำต้องมีการกล่าวโดยทั่วไปว่า==ไม่ใช่ทางเลือกที่เป็นไปequalsได้ อย่างไรก็ตามเมื่อเป็นเช่นenumนั้นมีความแตกต่างที่สำคัญสองประการที่ควรพิจารณา:

== ไม่เคยโยน NullPointerException

enum Color { BLACK, WHITE };

Color nothing = null;
if (nothing == Color.BLACK);      // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException

== อาจมีการตรวจสอบความเข้ากันได้ของประเภทในเวลารวบรวม

enum Color { BLACK, WHITE };
enum Chiral { LEFT, RIGHT };

if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine
if (Color.BLACK == Chiral.LEFT);      // DOESN'T COMPILE!!! Incompatible types!

ควร==ใช้เมื่อมีผล?

โบลชกล่าวโดยเฉพาะว่าคลาสที่ไม่เปลี่ยนรูปซึ่งมีการควบคุมอินสแตนซ์ที่เหมาะสมสามารถรับประกันกับลูกค้าที่==ใช้งานได้ enumมีการกล่าวถึงโดยเฉพาะเพื่อเป็นตัวอย่าง

รายการที่ 1: พิจารณาวิธีการโรงงานแบบคงที่แทนการก่อสร้าง

[ ... ] มันจะช่วยให้ระดับไม่เปลี่ยนรูปเพื่อให้การรับประกันว่าไม่มีสองกรณีเท่ากับอยู่: ถ้าหากa.equals(b) a==bหากคลาสทำการรับประกันนี้ลูกค้าจะสามารถใช้==โอเปอเรเตอร์แทนequals(Object)วิธีการซึ่งอาจส่งผลให้ประสิทธิภาพดีขึ้น ประเภท Enum ให้การรับประกันนี้

เพื่อสรุปข้อโต้แย้งสำหรับการใช้==บนenumคือ:

  • มันได้ผล.
  • มันเร็วกว่า
  • ปลอดภัยในเวลาทำงาน
  • การรวบรวมเวลาปลอดภัยยิ่งขึ้น

27
คำตอบที่ดี แต่ ... 1. ใช้งานได้ : เห็นด้วย 2. เร็วกว่า : พิสูจน์ด้วย enums :) 3. ปลอดภัยกว่าเวลาทำงาน : Color nothing = null;เป็นข้อบกพร่อง IMHO และควรได้รับการแก้ไข enum ของคุณมีสองค่าไม่ใช่สาม ( ดูความคิดเห็นของ Tom Hawtin) 4. ปลอดภัยกว่าในการรวบรวมเวลา : ตกลง แต่equalsจะกลับมาfalseอีก ในตอนท้ายฉันไม่ได้ซื้อฉันชอบequals()ความสามารถในการอ่าน (ดูความคิดเห็นของ Kevin)
Pascal Thivent

201
เป็นเครื่องหมายสีดำสำหรับ Java ที่บางคนคิดว่าfoo.equals(bar)สามารถอ่านได้มากกว่าfoo == bar
Bennett McElwee

19
ใช้งานได้: จนกว่าคุณจะต้องการแทนที่ enum ด้วยคลาสเป็นส่วนหนึ่งของการปรับโครงสร้างใหม่ ขอให้โชคดีในการค้นหารหัสทั้งหมดโดยใช้ == ซึ่งจะแตก มันเร็วกว่า: แม้ว่าจะเป็นจริง (สงสัย) แต่ Knuth ก็อ้างถึงการเพิ่มประสิทธิภาพก่อนวัยอันควร ปลอดภัยในขณะใช้งาน: "ปลอดภัย" ไม่ใช่คำแรกที่ควรคำนึงถึงหากการใช้ == เป็นสิ่งเดียวที่แยกคุณจาก NullPointerException ปลอดภัยในเวลารวบรวม: ไม่ได้จริงๆ มันสามารถป้องกันคุณจากความผิดพลาดเบื้องต้นของการเปรียบเทียบชนิดผิด แต่อีกครั้งถ้านั่นเป็นวิธีที่โปรแกรมเมอร์ของคุณโง่ "ปลอดภัย" เป็นสิ่งหนึ่งที่คุณไม่ได้ทำ
laszlok

35
"ถ้านั่นเป็นสิ่งที่โปรแกรมเมอร์ของคุณโง่" ปลอดภัย "เป็นสิ่งหนึ่งที่คุณไม่ได้ทำ" - ฉันไม่เห็นด้วยกับคำพูดนี้ นี่คือสิ่งที่การตรวจสอบประเภทเป็นเรื่องเกี่ยวกับ: การป้องกันข้อผิดพลาด "โง่" ในเวลารวบรวมดังนั้นแม้กระทั่งก่อนที่รหัสจะทำงาน แม้แต่คนที่ฉลาดก็ทำผิดพลาดได้ แต่รับประกันได้ดีกว่าสัญญา
ymajoros

7
@laszlok: แน่นอน แต่ถ้าสิ่งต่าง ๆ สามารถล้มเหลวพวกเขาก็จะ การมีรั้วสำหรับความผิดพลาดโง่ ๆ นั้นเป็นสิ่งที่ดีเสมอ มีพื้นที่เหลือเฟือที่จะสร้างสรรค์สำหรับข้อบกพร่องเล็ก ๆ น้อย ๆ ให้คอมไพเลอร์จัดการกับสิ่งนี้ก่อนที่คุณจะพยายามเรียกใช้รหัสของคุณ
ymajoros

88

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

ในบันทึกย่อด้านข้างไม่จำเป็นต้องใช้==ในการเขียนรหัสที่ปลอดภัยถ้าคุณเขียนequals()สิ่งนี้:

public useEnums(final SomeEnum a) {
    if (SomeEnum.SOME_ENUM_VALUE.equals(a)) {
        
    }
    
}

นี่คือวิธีปฏิบัติที่ดีที่สุดที่รู้จักกันในชื่อเปรียบเทียบค่าคงที่จากทางซ้ายที่คุณควรปฏิบัติตามอย่างแน่นอน


9
ฉันทำสิ่งนี้เมื่อรับ.equals()ค่าสตริง แต่ฉันยังคงคิดว่ามันเป็นวิธีเส็งเคร็งในการเขียนโค้ดที่ปลอดภัย ฉันอยากจะมีโอเปอเรเตอร์มากกว่า (หรือวิธีการ แต่ฉันรู้ว่า [null object] .equals จะไม่ปลอดภัยใน Java เนื่องจากการทำงานของตัวดำเนินการ dot) ที่ปลอดภัยเสมอโดยไม่คำนึงถึง สั่งซื้อได้ใช้ใน. ความหมายที่ "เท่ากับ" ผู้ประกอบการควรเสมอการเดินทาง
Matt Ball

2
เพราะ Java ไม่มีผู้ให้บริการการนำทางที่ปลอดภัยของ Groovy ( ?.) ฉันจะใช้วิธีนี้ต่อไปเมื่อเปรียบเทียบกับค่าคงที่และ TBH ฉันไม่คิดว่ามันจะเสแสร้ง
Pascal Thivent

32
nullenum โดยทั่วไปจะมีข้อผิดพลาด คุณมีการแจกแจงค่าที่เป็นไปได้ทั้งหมดและนี่คืออีกค่าหนึ่ง!
Tom Hawtin - tackline

8
ยกเว้นค่าที่มีคำอธิบายประกอบอย่างชัดเจนว่า@Nullableฉันพิจารณาเปรียบเทียบค่าคงที่จากด้านซ้ายกับ antipattern เพราะจะกระจายความคลุมเครือเกี่ยวกับค่าที่สามารถหรือไม่สามารถเป็นโมฆะ ประเภท Enum ไม่ควรจะเป็น@Nullableดังนั้นค่า null จะเป็นข้อผิดพลาดในการเขียนโปรแกรม ในกรณีเช่นนี้ยิ่งคุณโยน NPE ได้เร็วเท่าใดโอกาสที่คุณจะพบข้อผิดพลาดในการเขียนโปรแกรมของคุณก็จะยิ่งมากขึ้นเท่านั้น ดังนั้น "แนวปฏิบัติที่ดีที่สุด ... ที่คุณควรทำตามอย่างแน่นอน" นั้นผิดพลาดเมื่อพูดถึงประเภทของ enum
Tobias

24
เปรียบเทียบค่าคงที่จากด้านซ้ายแนวปฏิบัติที่ดีที่สุดเช่นภาษาอังกฤษสไตล์โยดาที่ดีที่สุดคือ
maaartinus

58

อย่างที่คนอื่น ๆ พูดกันทั้งสองอย่าง==และ.equals()ทำงานในกรณีส่วนใหญ่ ความแน่นอนของเวลาในการคอมไพล์ที่คุณไม่ได้เปรียบเทียบกับประเภทของวัตถุที่คนอื่น ๆ ชี้ให้เห็นนั้นถูกต้องและเป็นประโยชน์อย่างไรก็ตามข้อผิดพลาดชนิดหนึ่งของการเปรียบเทียบวัตถุของเวลารวบรวมสองประเภทที่แตกต่างกันก็จะถูกค้นพบโดย FindBugs การตรวจสอบเวลาคอมไพล์ Eclipse / IntelliJ) ดังนั้นคอมไพเลอร์ Java จึงพบว่ามันไม่ได้เพิ่มความปลอดภัยมากนัก

อย่างไรก็ตาม:

  1. ความจริงที่ว่า==ไม่เคยพ่น NPE ในใจของฉันเป็นข้อเสีย==ของ ไม่ควรมีความจำเป็นที่จะต้องมีenumประเภทnullเนื่องจากสถานะพิเศษใด ๆ ที่คุณอาจต้องการให้แสดงผ่านnullสามารถเพิ่มลงในenumอินสแตนซ์เพิ่มเติมได้ หากเป็นเรื่องไม่คาดคิดnullฉันควรมี NPE มากกว่าที่==จะประเมินว่าเป็นเท็จ ดังนั้นผมจึงไม่เห็นด้วยกับมันปลอดภัยที่ใช้เวลาความเห็น; ดีกว่าที่จะได้รับเป็นนิสัยไม่เคยที่จะให้ค่าเป็นenum@Nullable
  2. โต้แย้งว่า==เป็นได้เร็วขึ้นนอกจากนี้ยังปลอม ในกรณีส่วนใหญ่คุณจะเรียก.equals()ตัวแปรที่มีชนิดรวบรวมเวลาเป็นชั้น enum และในกรณีที่คอมไพเลอร์สามารถรู้ได้ว่านี้เป็นเช่นเดียวกับ==(เพราะenum's equals()วิธีการไม่สามารถแทนที่) และสามารถเพิ่มประสิทธิภาพการเรียกใช้ฟังก์ชัน ไป ฉันไม่แน่ใจว่าคอมไพเลอร์ในปัจจุบันทำเช่นนี้หรือไม่ แต่หากไม่เป็นเช่นนั้นและกลายเป็นปัญหาด้านประสิทธิภาพใน Java โดยรวมแล้วฉันควรแก้ไขคอมไพเลอร์มากกว่าให้โปรแกรมเมอร์ Java 100,000 คนเปลี่ยนสไตล์การเขียนโปรแกรมให้เหมาะสม คุณลักษณะด้านประสิทธิภาพของเวอร์ชันคอมไพเลอร์โดยเฉพาะ
  3. enumsเป็นวัตถุ สำหรับทุกประเภทวัตถุอื่น ๆ เปรียบเทียบมาตรฐานคือไม่.equals() ==ฉันคิดว่ามันอันตรายที่จะทำการยกเว้นenumsเพราะคุณอาจบังเอิญเปรียบเทียบวัตถุกับ==แทนที่จะเป็นequals()โดยเฉพาะอย่างยิ่งถ้าคุณปรับโครงสร้างenumเข้าไปในชั้นที่ไม่ใช่ enum ในกรณีของการปรับโครงสร้างดังกล่าวจุดทำงานจากด้านบนผิด หากต้องการโน้มน้าวตัวเองว่าการใช้งาน==ถูกต้องคุณต้องตรวจสอบว่าคุณค่าของคำถามนั้นenumเป็นแบบดั้งเดิมหรือไม่ ถ้าไม่ใช่enumคลาสก็ผิด แต่พลาดง่ายเพราะรหัสจะคอมไพล์ กรณีเดียวเมื่อมีการใช้.equals()จะผิดคือถ้าค่าในคำถามเป็นพื้นฐาน ในกรณีนั้นรหัสจะไม่รวบรวมดังนั้นจึงเป็นเรื่องยากที่จะพลาด ดังนั้นจึง.equals()ง่ายต่อการระบุว่าถูกต้องและปลอดภัยกว่าการปรับโครงสร้างในอนาคต

ฉันคิดว่าภาษาจาวาควรกำหนด == บน Objects to call .equals () ทางด้านซ้ายมือและแนะนำตัวดำเนินการแยกต่างหากสำหรับเอกลักษณ์ของวัตถุ แต่นั่นไม่ใช่วิธีที่ Java กำหนดไว้

โดยสรุปฉันยังคงคิดว่าข้อโต้แย้งมีประโยชน์ในการใช้.equals()กับenumประเภท


4
เกี่ยวกับจุดที่ 3 ฉันสามารถใช้enumเป็นswitchเป้าหมายเพื่อให้พวกเขาพิเศษ Stringเป็นพิเศษเช่นกัน
CurtainDog

ไวยากรณ์สำหรับคำสั่ง switch ไม่มีทั้ง == หรือ. equals () ดังนั้นฉันไม่เห็นว่าจุดของคุณคืออะไร จุดของฉัน 3. ) เป็นเรื่องเกี่ยวกับรหัสง่าย ๆ คือการตรวจสอบสำหรับผู้อ่าน ความหมายความเท่าเทียมกันของข้อความสั่งของ Switch นั้นถูกต้องตราบใดที่คำสั่ง switch รวบรวม
Tobias

17

ฉันชอบที่จะใช้==แทนequals:

เหตุผลอื่นนอกเหนือจากที่กล่าวถึงแล้วในที่นี้คือคุณสามารถแนะนำข้อผิดพลาดโดยไม่ทราบหรือไม่ สมมติว่าคุณมี enums นี้ซึ่งเหมือนกัน แต่ใน pacakges ที่แยกจากกัน (มันไม่ธรรมดา แต่มันอาจเกิดขึ้นได้):

Enum แรก :

package first.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

Enum ที่สอง:

package second.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

จากนั้นสมมติว่าคุณใช้เท่ากับเช่นถัดไปitem.categoryซึ่งเป็นfirst.pckg.Categoryแต่คุณนำเข้า enum ที่สอง ( second.pckg.Category) แทนอันแรกโดยที่ไม่ทราบว่า:

import second.pckg.Category;
...

Category.JAZZ.equals(item.getCategory())

ดังนั้นคุณจะได้รับ allways falseเนื่องจากเป็น enum ที่แตกต่างกันถึงแม้ว่าคุณจะคาดหวังเพราะความจริงคือitem.getCategory() JAZZและอาจเป็นเรื่องยากที่จะเห็น

ดังนั้นหากคุณใช้โอเปอเรเตอร์แทนคุณ==จะมีข้อผิดพลาดในการคอมไพล์:

โอเปอเรเตอร์ == ไม่สามารถใช้ได้กับ "second.pckg.Category", "first.pckg.Category"

import second.pckg.Category; 
...

Category.JAZZ == item.getCategory() 

คะแนนที่ดีมากที่คุณพูดถึง ดังนั้นสิ่งที่ฉันจะทำคือ applay myenum.value () จากนั้นทำ == เปรียบเทียบเพื่อความปลอดภัยของ NPE
Java Main

14

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

import java.util.Date;

public class EnumCompareSpeedTest {

    static enum TestEnum {ONE, TWO, THREE }

    public static void main(String [] args) {

        Date before = new Date();
        int c = 0;

        for(int y=0;y<5;++y) {
            for(int x=0;x<Integer.MAX_VALUE;++x) {
                if(TestEnum.ONE.equals(TestEnum.TWO)) {++c;}
                if(TestEnum.ONE == TestEnum.TWO){++c;}              
            }
        }

        System.out.println(new Date().getTime() - before.getTime());
    }   

}

แสดงความคิดเห็น IFs ทีละหนึ่ง นี่คือทั้งสองเปรียบเทียบจากด้านบนในรหัสไบต์ถอดประกอบ:

 21  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 24  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 27  invokevirtual EnumCompareSpeedTest$TestEnum.equals(java.lang.Object) : boolean [28]
 30  ifeq 36

 36  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 39  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 42  if_acmpne 48

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

ฉันรันการทดสอบนี้หลายครั้งโดยใช้ IFs ทั้งคู่ทีละครั้ง "==" เร็วขึ้นเล็กน้อย


ฉันสงสัยว่า compiler branch-prediction อาจทำให้การทดสอบนี้ไม่ถูกต้อง คอมไพเลอร์สมาร์ทจะรับรู้ว่าข้อความทั้งสองนั้นหากคำสั่งจะประเมินเป็นเท็จเสมอและหลีกเลี่ยงการเปรียบเทียบหลายรายการ เรียบเรียงมาร์ทจริงๆก็อาจจะรู้ว่าค่าใน Y และ x ลูปจะไม่มีผลกระทบต่อผลและเพิ่มประสิทธิภาพออกสิ่งทั้งหมด ...
Darrel ฮอฟแมน

ทำได้ แต่ไม่แน่นอน ฉันแสดง bytecode ที่สร้างโดยผู้แปลจริงในคำตอบของฉัน
ChrisCantrell

คุณทั้งคู่สับสน :-) การคาดคะเนสาขาทำงานในเวลาทำงานดังนั้นโค้ดไบต์ต่างกันจึงไม่เกี่ยวข้องกันมาก อย่างไรก็ตามในกรณีนี้การทำนายสาขาจะช่วยให้ทั้งสองกรณีเท่ากัน
vidstige

7
ใครสน? ยกเว้นว่าคุณกำลังเปรียบเทียบจำนวนหลายพันครั้งภายในลูประหว่างวิดีโอเกมนาโนวินาทีพิเศษนั้นไม่มีความหมาย
user949300

bytecode ค่อนข้างไม่เกี่ยวข้องกับประสิทธิภาพเว้นแต่คุณจะบังคับให้ใช้โหมดตีความ เขียนเกณฑ์มาตรฐานJMHเพื่อดูว่าประสิทธิภาพนั้นเหมือนกันทุกประการ
maaartinus


7

TL; DR

ตัวเลือกอื่นคือObjects.equalsวิธีการยูทิลิตี้

Objects.equals( thisEnum , thatEnum )

Objects.equals เพื่อความปลอดภัย null

เท่ากับโอเปอเรเตอร์ == แทน. equals ()

ฉันควรใช้โอเปอเรเตอร์แบบใด

ตัวเลือกที่สามคือequalsวิธีสแตติกที่พบในObjectsคลาสยูทิลิตี้ที่เพิ่มใน Java 7และใหม่กว่า

ตัวอย่าง

นี่คือตัวอย่างการใช้Monthenum

boolean areEqual = Objects.equals( Month.FEBRUARY , Month.JUNE ) ;  // Returns `false`.

ประโยชน์ที่ได้รับ

ฉันพบประโยชน์สองสามประการสำหรับวิธีนี้:

  • Null ความปลอดภัย
    • ทั้ง Null เป็นโมฆะ true
    • เป็นโมฆะ null false
    • ไม่มีความเสี่ยงในการขว้าง NullPointerException
  • กะทัดรัดอ่านง่าย

มันทำงานอย่างไร

ตรรกะใช้โดยObjects.equalsอะไร

ดูด้วยตัวคุณเองจากซอร์สโค้ด Java 10ของOpenJDK :

return (a == b) || (a != null && a.equals(b));

6

การใช้สิ่งอื่นนอกเหนือจาก==การเปรียบเทียบค่าคงที่ enum นั้นเป็นเรื่องไร้สาระ มันเหมือนกับการเปรียบเทียบclassวัตถุกับequals - อย่าทำมัน!

อย่างไรก็ตามมีข้อผิดพลาดที่น่ารังเกียจ (BugId 6277781 ) ใน Sun JDK 6u10 และรุ่นก่อนหน้าซึ่งอาจน่าสนใจด้วยเหตุผลทางประวัติศาสตร์ ข้อผิดพลาดนี้ทำให้ไม่สามารถใช้งาน==deserialized enums ได้อย่างเหมาะสมแม้ว่าจะเป็นกรณีมุมก็ตาม


4

Enums เป็นคลาสที่คืนค่าอินสแตนซ์เดียว (เช่น singletons) สำหรับค่าคงที่การแจงนับแต่ละรายการที่ประกาศโดยpublic static final field(ไม่เปลี่ยนรูป) เพื่อให้==ผู้ปฏิบัติงานสามารถใช้ตรวจสอบความเท่าเทียมกันแทนที่จะใช้equals()วิธีการ


1

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

แต่การใช้ == เพราะใช้งานได้กับ enums หมายความว่าโค้ดทั้งหมดของคุณมีการใช้ควบคู่กับ enum อย่างแน่นหนา

ตัวอย่างเช่น: Enums สามารถใช้อินเตอร์เฟสได้ สมมติว่าคุณกำลังใช้ enum ซึ่งใช้ Interface1 หากภายหลังใครบางคนเปลี่ยนหรือแนะนำคลาสใหม่ Impl1 เป็นการใช้งานอินเทอร์เฟซเดียวกัน จากนั้นหากคุณเริ่มใช้งานอินสแตนซ์ของ Impl1 คุณจะมีรหัสจำนวนมากที่จะเปลี่ยนแปลงและทดสอบเนื่องจากการใช้งานก่อนหน้านี้ของ ==

ดังนั้นจึงเป็นการดีที่สุดที่จะปฏิบัติตามสิ่งที่ถือว่าเป็นแนวปฏิบัติที่ดีเว้นแต่จะได้รับความสมเหตุสมผล


คำตอบที่ดี แต่กล่าวแล้วที่นี่
shmosel

หนอ ณ จุดนั้นคำถามจะเกี่ยวกับว่าคุณใช้ == หรือเท่ากับบนอินเทอร์เฟซ รวมถึงคำถามทุกประเภทเกี่ยวกับว่ามันสมเหตุสมผลหรือไม่ที่จะแทนที่การใช้งานของประเภทที่ไม่เปลี่ยนรูปแบบด้วยการใช้งานที่ไม่แน่นอน และอาจเป็นการดีที่จะทราบว่าการปฏิบัติที่ดีคืออะไรก่อนที่คุณจะกังวลเกี่ยวกับการได้รับความยุติธรรม (imho == เป็นการฝึกฝนที่ดีกว่า)
Robin Davies

1

หนึ่งในกฎ Sonar Enum values should be compared with "=="คือ เหตุผลมีดังนี้

การทดสอบความเท่าเทียมกันของค่า enum ด้วยequals()นั้นใช้ได้อย่างสมบูรณ์เพราะ enum เป็นวัตถุและนักพัฒนา Java ทุกคน==ไม่ควรใช้เพื่อเปรียบเทียบเนื้อหาของวัตถุ ในเวลาเดียวกันใช้==กับ enums:

  • ให้การเปรียบเทียบที่คาดหวัง (เนื้อหา) เช่นเดียวกับ equals()

  • ปลอดภัยกว่า null equals()

  • ให้การตรวจสอบเวลาแบบคงที่ (แบบคงที่) มากกว่าการตรวจสอบแบบรันไทม์

ด้วยเหตุผลเหล่านี้คุณ==ควรเลือกequals()ใช้

สุดท้าย แต่ไม่น้อยที่==ใน enums คือเนื้อหาที่อ่านได้มากขึ้น (verbose equals()น้อยกว่า)


0

ในระยะสั้นทั้งสองมีข้อดีและข้อเสีย

ในอีกด้านหนึ่งมันมีข้อดีที่จะใช้==ตามที่อธิบายไว้ในคำตอบอื่น ๆ

ในทางกลับกันถ้าคุณด้วยเหตุผลใด ๆ แทนที่ enums ด้วยวิธีการที่แตกต่างกัน (อินสแตนซ์ชั้นเรียนปกติ) มีการใช้==กัดคุณ (BTDT.)


-1

ฉันต้องการเติมเต็มคำตอบ polygenelubricants:

ฉันชอบตัวเองเท่ากับ () แต่มันเป็นทะเลสาบตรวจสอบความเข้ากันได้ของประเภท ซึ่งฉันคิดว่าเป็นข้อ จำกัด ที่สำคัญ

เมื่อต้องการให้ตรวจสอบความเข้ากันได้ของชนิดในขณะรวบรวมให้ประกาศและใช้ฟังก์ชันที่กำหนดเองใน enum ของคุณ

public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable

ด้วยวิธีนี้คุณจะได้รับประโยชน์ทั้งหมดจากโซลูชันทั้งสอง: การป้องกัน NPE รหัสที่อ่านง่ายและการตรวจสอบความเข้ากันได้ของประเภทในเวลารวบรวม

ฉันยังแนะนำให้เพิ่มค่า UNDEFINED สำหรับ enum


4
ทำไมการแก้ปัญหานี้ถึงดีกว่า==? เมื่อ==คุณได้รับการป้องกัน NPE รหัสที่อ่านง่ายและการตรวจสอบความเข้ากันได้ของประเภทเวลาคอมไพล์แล้วคุณจะได้รับทั้งหมดโดยไม่ต้องเขียนวิธีการใด ๆ ที่เหมือนกัน
Matt Ball

1
UNDEFINEDคุ้มค่าน่าจะเป็นความคิดที่ดี แน่นอนใน Java 8 คุณจะต้องใช้Optionalแทน
โทมัส

-7

==สามารถโยนNullPointerExceptionหากประเภทดั้งเดิมจะถูกเปรียบเทียบกับรุ่นระดับของมัน ตัวอย่างเช่น:

private static Integer getInteger() {
    return null;
}

private static void foo() {
    int a = 10;

    // Following comparison throws a NPE, it calls equals() on the 
    // non-primitive integer which is itself null. 
    if(a == getInteger()) { 
        // Some code
    }
}

2
ขอบเขตค่อนข้างชัดเจนสำหรับคำถามนี้และประเภทดั้งเดิมไม่อยู่ในขอบเขต
Tom

@ Tom อภิปรายเกิดขึ้นที่นี่เป็นความเข้าใจผิดที่ไม่สามารถโยน== NPEsคำถามนี้มีคำตอบเพียงพอ แต่อาจเป็นการอ้างอิงที่ดีในกรณีที่มีคนอย่างฉันที่ใช้เวลา 2 ชั่วโมงในการรับข้อผิดพลาด / คุณลักษณะอ่านข้อความนี้
ayushgp

1
ฉันไม่สามารถโยน NPE ได้เมื่อคุณไม่สนใจหัวข้อของคำถามนี้ และแม้ว่าคุณจะเก็บคำตอบนี้ไว้ที่นี่คุณคิดว่าคนที่มีปัญหาเดียวกันกับที่คุณเคยพบคำตอบนี้โดยการค้นหาสิ่งที่แตกต่างกันหรือไม่? บุคคลนั้นจะต้องค้นหา enums ที่เห็นได้ชัดว่าไม่ได้ใช้ คำตอบนี้เหมาะสมสำหรับคำถามนี้: stackoverflow.com/questions/7520432/…
Tom
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.