assertEquals ของ Java นั้นเชื่อถือได้หรือไม่?


199

ฉันรู้ว่ามีปัญหาบางอย่างเมื่อเปรียบเทียบสอง== Stringsดูเหมือนว่าString.equals()เป็นวิธีที่ดีกว่า ดีที่ฉันทำทดสอบ JUnit assertEquals(str1, str2)และความชอบของฉันคือการใช้งาน นี่เป็นวิธีที่เชื่อถือได้ในการยืนยันสองสตริงที่มีเนื้อหาเดียวกันหรือไม่? ฉันจะใช้assertTrue(str1.equals(str2))แต่แล้วคุณไม่ได้รับประโยชน์จากการเห็นสิ่งที่คาดหวังและค่าที่แท้จริงคือความล้มเหลว

ในบันทึกที่เกี่ยวข้องไม่มีใครมีลิงค์ไปยังหน้าหรือเธรดที่อธิบายปัญหาด้วยstr1 == str2?


1
หากคุณไม่แน่ใจคุณสามารถอ่านรหัสหรือ Javadoc BTW ถ้าคุณต้องการทดสอบพวกเขาเป็นวัตถุเดียวกันคุณสามารถใช้ assertSame
Peter Lawrey

2
หาก str1 และ str2 เป็นโมฆะ assertEquals () เป็นจริง แต่ assertTrue (str1.equals (str2)) จะส่งข้อยกเว้น ตัวอย่างแรกจะพิมพ์ข้อความแสดงข้อผิดพลาดที่มีประโยชน์เช่นเนื้อหาของ str1 และ str2 โดยที่สองไม่ได้
Peter Lawrey

คำตอบ:


274

คุณควรเสมอใช้.equals()เมื่อเปรียบเทียบStringsในชวา

JUnit เรียกวิธีการในการตรวจสอบความเท่าเทียมกันในวิธีการ.equals()assertEquals(Object o1, Object o2)

assertEquals(string1, string2)ดังนั้นคุณจะแน่นอนปลอดภัยใช้ (เพราะStringเป็นObjects)

นี่คือการเชื่อมโยงไปยังคำถาม Stackoverflow ที่ดีเกี่ยวกับบางส่วนของความแตกต่างระหว่างและ==.equals()


12
IIRC assertEquals () สำเร็จถ้าสตริงทั้งสองเป็นโมฆะ หากนี่ไม่ใช่สิ่งที่คุณต้องการให้เรียก assertNotNull () เช่นกัน
finnw

10
นอกจากนี้หากคุณต้องการที่จะทดสอบ == คุณสามารถเรียก assertSame ()
james

7
ฉันจะไม่พูดเสมอ ; บางครั้งต้องการความเท่าเทียมกันของการอ้างอิงถึงแม้จะเป็นสตริง
Karu

30

assertEqualsใช้equalsวิธีการเปรียบเทียบ มีการยืนยันที่แตกต่างกันassertSameซึ่งใช้ตัว==ดำเนินการ

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

เวลาเปรียบเทียบ: ลองนึกภาพว่าStringวัตถุแต่ละชิ้นเป็นกระดาษที่มีบางสิ่งเขียนอยู่ สมมติว่าฉันมีกระดาษสองแผ่นที่เขียนด้วย "Foo" ลงบนพวกเขาและอีกชิ้นที่เขียนด้วย "บาร์" ไว้ ถ้าฉันเอากระดาษสองชิ้นแรกมาและใช้==เพื่อเปรียบเทียบมันจะกลับมาfalseเพราะมันเป็นคำถามที่ถามว่า ไม่จำเป็นต้องดูสิ่งที่เขียนบนกระดาษ ความจริงที่ว่าฉันให้มันสองชิ้นส่วนของกระดาษ (มากกว่าหนึ่งเดียวกันสองครั้ง) falseหมายความว่ามันจะกลับมา หากฉันใช้equalsแต่equalsวิธีการที่จะอ่านสองชิ้นของกระดาษและเห็นว่าพวกเขาพูดในสิ่งเดียวกัน ( "ฟู") trueและดังนั้นจึงจะกลับ

บิตที่ทำให้สับสนกับ Strings คือ Java มีแนวคิดของ "interning" Strings และนี่คือ (อย่างมีประสิทธิภาพ) ดำเนินการโดยอัตโนมัติในตัวอักษรสตริงใด ๆ ในรหัสของคุณ ซึ่งหมายความว่าหากคุณมีตัวอักษรสตริงเทียบเท่าสองตัวในรหัสของคุณ (แม้ว่าพวกเขาจะอยู่ในชั้นเรียนที่แตกต่างกัน) พวกเขาทั้งสองจะอ้างถึงStringวัตถุเดียวกัน สิ่งนี้ทำให้==ผู้ปฏิบัติงานกลับมาtrueบ่อยกว่าที่คาดไว้


"นั่นคือ a == b ตรวจสอบเพื่อดูว่า a และ b เป็นวัตถุเดียวกันหรือไม่" ในทางเทคนิคมันตรวจสอบว่า a และ b อ้างถึงวัตถุเดียวกันเนื่องจาก a และ b เป็นการอ้างอิง ถ้าฉันไม่ผิด
บ๊อบ

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

7

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

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


4
public class StringEqualityTest extends TestCase {
    public void testEquality() throws Exception {
        String a = "abcde";
        String b = new String(a);
        assertTrue(a.equals(b));
        assertFalse(a == b);
        assertEquals(a, b);
    }
}

3

ใช่มันถูกใช้ตลอดเวลาสำหรับการทดสอบ มีโอกาสมากที่กรอบการทดสอบใช้. Equals () สำหรับการเปรียบเทียบเช่นนี้

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

http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/


3

JUnit ไม่แน่นอนโทรassertEquals(obj1, obj2)obj1.equals(obj2)

นอกจากนี้ยังมีassertSame(obj1, obj2)สิ่งที่ทำobj1 == obj2(เช่นตรวจสอบobj1และobj2อ้างอิงตัวอย่างเดียวกัน ) ซึ่งเป็นสิ่งที่คุณพยายามหลีกเลี่ยง

ดังนั้นคุณสบายดี


0

" ==ผู้ประกอบการตรวจสอบเพื่อดูว่าทั้งสองObjectsเหมือนกันObjectหรือไม่"

http://leepoint.net/notes-java/data/strings/12stringcomparison.html

Stringเป็นObjectin java ดังนั้นจึงอยู่ในหมวดหมู่ของกฎการเปรียบเทียบ


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