(String) หรือ. toString ()?


89

ฉันมีวิธีการที่มีObject oพารามิเตอร์

ในวิธีนี้ฉันรู้ว่ามีStringใน "o" ซึ่งไม่เป็นโมฆะ ไม่จำเป็นต้องตรวจสอบหรือทำอย่างอื่น ฉันต้องปฏิบัติต่อมันเหมือนกับStringสิ่งของ

แค่อยากรู้อยากเห็น - อะไรถูกกว่า - โยนให้Stringหรือใช้Object.toString()? หรือมันเหมือนกันตามเวลา - / cpu- / mem- ราคา?

อัปเดต: วิธีนี้ยอมรับObjectเนื่องจากเป็นการใช้งานอินเทอร์เฟซ ไม่มีวิธีใดในการเปลี่ยนประเภทพารามิเตอร์

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


1
ในโลก. NET เราวัดได้และ ToString () เร็วกว่า เมื่อพิจารณาถึงสาเหตุที่เป็นเช่นนั้นก็เกือบจะเป็นจริงเช่นเดียวกันกับ JVM
Joshua

คำตอบ:


73

การส่งไปยัง String มีราคาถูกกว่าเนื่องจากไม่จำเป็นต้องมีการเรียกใช้ฟังก์ชันภายนอกเพียงแค่ตรวจสอบประเภทภายใน


4
คุณได้ทดสอบกับ JRE หลายตัวแล้วหรือยัง? ฉันได้เห็นผลลัพธ์ที่น่าประหลาดใจสำหรับสถานการณ์นี้ใน. NET ตามความเป็นจริงฉันสงสัยว่าประสิทธิภาพจะมีความสำคัญในชีวิตจริง - แต่การคัดเลือกนักแสดงจะดีกว่าจากมุมมองของการเข้ารหัสเชิงป้องกัน
Jon Skeet

การเรียกเมธอดควรเป็นแบบอินไลน์ การใช้ generics เพื่อลบแคสต์ (Explicit) จะดีที่สุด
Tom Hawtin - แท็กไลน์

@ Jon Skeet: ฉันยอมรับว่าความแตกต่างของประสิทธิภาพจะไม่มากนัก @ Tom Hawtin: เนื่องจากไม่ทราบชนิดของวัตถุที่จะได้รับในเวลาคอมไพล์ฉันจึงไม่เห็นว่าการเรียกเมธอดสามารถอินไลน์ได้อย่างไร คุณช่วยชี้แจงได้ไหม
euphoria83

@ euphoria83: อินไลน์โดยคอมไพเลอร์ JIT ไม่ใช่โดย javac
Michael Myers

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

45

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


37

ตามการแสดงของ Silly: x.toString () vs (String) x

ในท้ายที่สุดผลลัพธ์ก็ชัดเจนอย่างน่าประหลาดใจ: อย่างน้อยสองเท่าในการส่ง Object to String เร็วกว่าการเรียก Object.toString ()


1
ฉันรันโค้ดนั้นตอนนี้ความแตกต่างเล็กน้อย (Mac, Java 8)
Stefan L

7

ถ้าคุณรู้ว่า Object o เป็น String ฉันจะบอกว่าแค่โยนมันเป็น String แล้วบังคับใช้แบบนั้น การเรียก toString () บนออบเจ็กต์ที่คุณรู้แน่นอนว่าเป็น String อาจเพิ่มความสับสน

ถ้า Object o เป็นอะไรก็ได้ที่ไม่ใช่ String คุณจะต้องเรียก toString ()


นี่คือคำตอบที่ถูกต้องสำหรับฉัน ทำไม? เนื่องจากการแคสต์(string)Registry.GetValue...มีข้อยกเว้นสำหรับการพยายามร่ายวัตถุ Int32 ในขณะที่Registry.GetValue...ToString()ทำงานได้ตามที่คาดไว้
แรงโน้มถ่วง

3

ฉันจะไม่กังวลกับประสิทธิภาพมากเกินไปหากการดำเนินการนี้เสร็จสิ้นแม้เพียงไม่กี่พันครั้งต่อวินาทีก็ไม่มีความแตกต่างที่จับต้องได้

อย่างไรก็ตามฉันจะกังวลเกี่ยวกับการ "รู้" ข้อมูลที่ป้อน คุณมีวิธีการที่ยอมรับObjectและคุณควรปฏิบัติเช่นนี้กล่าวคือคุณไม่ควร รู้อะไรเกี่ยวกับพารามิเตอร์นอกเหนือจากที่เป็นไปตามObjectอินเทอร์เฟซซึ่งจะมีtoString()วิธีการ ในกรณีนี้ฉันขอแนะนำอย่างยิ่งให้ใช้วิธีนั้นแทนการตั้งสมมติฐานอะไรเลย

OTOH ถ้าใส่เป็นเสมออย่างใดอย่างหนึ่ง Stringหรือnullเพียงแค่เปลี่ยนวิธีการที่จะยอมรับStrings และตรวจสอบอย่างชัดเจนสำหรับnulls (ซึ่งคุณควรจะทำยังไงเมื่อใดก็ตามที่การจัดการกับวิทยาการไม่ใช่ ... )


ฉันบอกว่าคำถามของฉันไม่มีความหมายที่มีค่า :) ฉันแค่อยากรู้ว่าอะไรถูกกว่าในทางทฤษฎี แต่ยังไง
ก็ตาม

ค่าใช้จ่ายจะขึ้นอยู่กับประสิทธิภาพของ VM ในการเรียกวิธีเสมือนเทียบกับการตรวจสอบประเภท นั่นคือการใช้งานเฉพาะ
Jon Skeet

2

ระบุว่าประเภทการอ้างอิงเป็น Object และ Objects ทั้งหมดมี toString () เพียงแค่เรียก object.toString () String.toString () ส่งคืนค่านี้

  • toString () คือรหัสที่จะพิมพ์น้อยกว่า
  • toString () น้อยกว่า bytecode
  • การหล่อเป็นการดำเนินการที่มีราคาแพง VS การเรียกหลายรูปแบบ
  • นักแสดงอาจล้มเหลว
  • ใช้ String.valueOf (object) ซึ่งเรียก object.toString () ถ้าไม่ใช่ null

1

หากสิ่งที่คุณมีใน "o" เป็นสตริงก็จะไม่มีความแตกต่างกันมากนัก (น่าจะแคสต์เร็วกว่า แต่นั่นเป็นสิ่งที่ใช้งาน VM / Library)

ถ้า "o" อาจไม่ใช่ String แต่ควรจะเป็น String ดังนั้นการแคสต์จะเป็นสิ่งที่คุณต้องการ (แต่คุณควรทำให้เมธอดใช้ String แทน Object)

ถ้า "o" เป็นประเภทใดก็ได้คุณต้องใช้ toString แต่อย่าลืมตรวจสอบค่าว่างก่อน

void foo(final Object o)
{
    final String str;

    // without this you would get a class cast exception
    // be wary of using instanceof though - it is usually the wrong thing to do
    if(o instanceof String)
    {
        str = (String)o;
    }    
}

หรือ

void foo(final Object o)
{
    final String str;

    // if you are 100% sure that o is not null then you can get rid of the else
    if(o != null)
    {
        str = o.toString();
    }
}

ฉันอยากจะเขียนโค้ดสุดท้ายเป็น:

void foo(final Object o)
{
    final String str;

    if(o == null)
    {
        throw new IllegalArgumentException("o cannot be null");
    }

    str = o.toString();
}

2 ตัวอย่างแรกจะไม่คอมไพล์จริงๆ ( finalตัวแปรอาจยังไม่ได้เตรียมใช้งาน) คุณต้องการสิ่งelseที่จะทำให้เกิดข้อยกเว้นหรือเริ่มต้นstrบางสิ่งบางอย่าง
Bruno Reis

1

ฉันพบว่าแปลกที่นักแสดงช้ากว่าการค้นหา vtable โดยนัยโดยการเรียกแบบ tostring


1

ไม่สามารถมี 'สตริงว่างใน o' ถ้า o เป็นโมฆะจะไม่มีสตริงว่างจะเป็นเพียงค่าว่าง เพียงตรวจสอบ o เป็นค่าว่างก่อน หากคุณแคสต์หรือเรียก ToString () บน null คุณจะหยุดทำงาน


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