ลองใช้ / จับบล็อกมีประสิทธิภาพหรือไม่


21

ควรใช้บล็อก catch สำหรับการเขียนลอจิกนั่นคือ handle flow control etc? หรือเพียงแค่โยนข้อยกเว้น? มันส่งผลต่อประสิทธิภาพหรือความสามารถในการบำรุงรักษาโค้ดหรือไม่?

อะไรคือผลข้างเคียง (ถ้ามี) ของการเขียนลอจิกใน catch block?

แก้ไข:

ฉันเคยเห็นคลาส Java SDK ซึ่งพวกเขาได้เขียนตรรกะภายใน catch block ตัวอย่างเช่น (ตัวอย่างข้อมูลมาจากjava.lang.Integerชั้นเรียน):

        try {
            result = Integer.valueOf(nm.substring(index), radix);
            result = negative ? new Integer(-result.intValue()) : result;
        } catch (NumberFormatException e) {
            String constant = negative ? new String("-" + nm.substring(index))
                                       : nm.substring(index);
            result = Integer.valueOf(constant, radix);
        }

แก้ไข 2 :

ฉันกำลังดูบทช่วยสอนที่พวกเขานับว่าเป็นข้อได้เปรียบในการเขียนตรรกะของกรณีพิเศษภายในข้อยกเว้น:

ข้อยกเว้นช่วยให้คุณสามารถเขียนโฟลว์หลักของโค้ดและจัดการกับกรณีพิเศษอื่น ๆ

แนวทางเฉพาะเมื่อเขียนตรรกะใน catch catch และเมื่อใด


12
@Coder ฉันคิดว่าคุณมากเกินไปเล็กน้อย โดยเฉพาะอย่างยิ่งเนื่องจาก API ที่มีอยู่มากมายคุณไม่สามารถหลีกเลี่ยงได้
CodesInChaos

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

4
@Coder ขึ้นอยู่กับ ฉันคิดว่าเมื่อทำ IO หรือเมื่อแยกวิเคราะห์ข้อมูลที่ซับซ้อนซึ่งมีการจัดรูปแบบอย่างถูกต้องเกือบตลอดเวลาการขว้างข้อยกเว้นเพื่อบ่งบอกถึงข้อผิดพลาดทำให้รหัสนั้นสะอาดกว่ามาก
CodesInChaos

1
@ รหัสใช่การประหารชีวิตอยู่ที่นั่นสำหรับวิธีที่จะบอกคุณว่ามันไม่สามารถทำสิ่งที่ถูกถามได้ แต่ข้อยกเว้นไม่ควรใช้สำหรับการควบคุมการไหลซึ่งเป็นสาเหตุที่ C # มีวิธี int.TryParse ที่ไม่ได้โยน
แอนดี้

1
@Coder: นั่นคือขยะที่สุด สิ่งที่ยอดเยี่ยมในรหัสหนึ่งระดับอาจไม่ได้ยอดเยี่ยมในอีก - หรือคุณอาจต้องการตัวอย่างเช่นนำเสนอหรือเพิ่มข้อผิดพลาดหรือข้อมูลการตรวจแก้จุดบกพร่องก่อนดำเนินการต่อ
DeadMG

คำตอบ:


46

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

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

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


1
+1 ทำคะแนนได้ดี ฉันคิดว่าการประมวลผลบางอย่างอาจใช้ได้ในการตรวจจับเช่นการเตรียมข้อความแสดงข้อผิดพลาดและการบันทึกข้อผิดพลาด การเพิ่มทรัพยากรที่มีราคาแพงเช่นการเชื่อมต่อฐานข้อมูลและการอ้างอิง COM (. NET) COM สามารถเพิ่มลงในบล็อกสุดท้ายได้
NoChance

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

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

3
+1 สำหรับประโยคสุดท้าย
FrustratedWithFormsDesigner

2
@ scarfridge: ฉันเห็นด้วยกับคุณอย่างสมบูรณ์ :) ไม่มีวิธี isInteger (String) ที่คืนค่ากลับบูลีนคือทั้งหมดที่ฉันหมายถึงด้วย "การออกแบบ API ที่ไม่ดี"
Michael Borgwardt

9

นี่คือสิ่งที่มีแนวโน้มที่จะขึ้นอยู่กับภาษาและกระบวนทัศน์

งานของฉันส่วนใหญ่จะทำใน Java (และบางครั้ง C ++) แนวโน้มคือการใช้ข้อยกเว้นสำหรับเงื่อนไขพิเศษเท่านั้น มีคำถามบางอย่างเกี่ยวกับ Stack Overflow เกี่ยวกับค่าใช้จ่ายด้านประสิทธิภาพของข้อยกเว้นใน Javaและอย่างที่คุณเห็นนั่นไม่ใช่เรื่องเล็กน้อยเลย นอกจากนี้ยังมีข้อกังวลอื่น ๆ เช่นความสามารถในการอ่านและการบำรุงรักษาของรหัส เมื่อใช้อย่างถูกต้องข้อยกเว้นสามารถมอบหมายข้อผิดพลาดในการจัดการส่วนประกอบที่เหมาะสม

อย่างไรก็ตามใน Python ความคิดที่ว่าจะเป็นการง่ายกว่าที่จะขอการให้อภัยมากกว่าการอนุญาต ในชุมชน Python สิ่งนี้เรียกว่าEAFPซึ่งตรงกันข้ามกับแนวทาง "look before you leap" ( LBYL ) ในภาษา C-style


2
+1 สำหรับการพูดถึงค่าใช้จ่ายโดยมีข้อยกเว้น ฉันทำ. NET และ (อย่างน้อยในเครื่องของฉัน) ฉันอาจรู้สึกเมื่อข้อยกเว้นกำลังจะเกิดขึ้นตามระยะเวลาที่ใช้ในบางกรณีเมื่อเทียบกับการดำเนินงานปกติอื่น ๆ
NoChance

2
@EmmadKareem ต่อเมื่อคุณมีตัวเชื่อมต่อดีบักเกอร์ คุณสามารถโยนหลายพันต่อวินาทีโดยไม่ต้องดีบักเกอร์
CodesInChaos

@CodeInChaos คุณถูกต้อง ฉันจะรู้ว่าผมเขียนเช่นรหัสสะอาดที่ไม่เคยได้รับใด ๆ ในเวลาทำงาน :)
NoChance

@EmmadKareem ขึ้นอยู่กับว่าจะเขียนแอปพลิเคชั่นเครือข่ายอย่างไรการจัดการการเชื่อมต่อหรือโปรโตคอลล้มเหลวจะได้รับการจัดการโดยมีข้อยกเว้น ข้อยกเว้นจำเป็นต้องรวดเร็วพอสมควรในแอปพลิเคชันดังกล่าวเพื่อหลีกเลี่ยงการโจมตี DoS เล็กน้อย
CodesInChaos

@CodeInChaos นี้เป็นสิ่งที่ดีที่จะรู้ ฉันล้อเล่นในความคิดเห็นล่าสุดของฉัน
NoChance

9

นั่นไม่ใช่วิธีที่ดีที่สุดในการคิดเกี่ยวกับ try / catch blocks วิธีคิดเกี่ยวกับ try / catch blocks คือ: ความล้มเหลวเกิดขึ้นที่ใดดีที่สุดในการจัดการกับความล้มเหลวเฉพาะนี้ นั่นอาจเป็นบรรทัดถัดไปของรหัสก็อาจเป็นยี่สิบระดับขึ้นสายโซ่ ไม่ว่าจะอยู่ที่ไหนก็ควรจะอยู่ที่ไหน

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

ส่วนสำคัญที่ต้องเข้าใจคือ: catch block == ฉันรู้วิธีจัดการกับสิ่งนี้


6

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

การจัดการโฟลว์ที่มีข้อยกเว้นช้าและไม่ถูกต้องทางความหมาย


4
ฉันรู้ว่าคุณกำลังพูดอะไร แต่ก็น่าสังเกตว่าข้อยกเว้นทั้งหมดนั้นคือการจัดการโฟลว์ของโปรแกรม - เพียงว่ามันควรจะใช้เพื่อควบคุมการไหลของข้อผิดพลาดพิเศษเท่านั้น ...
สูงสุด

ไม่มีแนวทางที่เฉพาะเจาะจงในการเขียนลอจิกใน catch block หรือไม่เมื่อไหร่?
HashimR

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

@JoonasPulakka ผมคิดว่าความคิดเห็นของคุณ WRT parsers จำนวนและจัดรูปแบบข้อความมีคุณสมบัติเป็นคำตอบที่ขนาดเต็มกับคำถามนี้
ริ้น

5

ควรใช้บล็อก catch สำหรับการเขียนลอจิกนั่นคือ handle flow control etc? หรือเพียงแค่โยนข้อยกเว้น? มันส่งผลต่อประสิทธิภาพหรือความสามารถในการบำรุงรักษาโค้ดหรือไม่?

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

รหัสนั้นง่ายที่สุดที่จะเข้าใจเมื่อการกระทำตามลำดับง่ายโดยไม่มีเงื่อนไข ข้อยกเว้นปรับปรุงการบำรุงรักษาโดยการลบการตรวจสอบข้อผิดพลาดจากการไหลปกติ ไม่สำคัญว่าการดำเนินการจะตามโฟลว์ปกติ 99.9% ของเวลาหรือ 50% ของเวลาหรือ 20% ของเวลา

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

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


1

บล็อก catch ไม่ควรใช้สำหรับการเขียนตรรกะโค้ด ควรใช้เพื่อการจัดการข้อผิดพลาดเท่านั้น ตัวอย่างคือ (1) ล้างทรัพยากรที่จัดสรรใด ๆ (2) พิมพ์ข้อความที่มีประโยชน์และ (3) ออกอย่างสง่างาม

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

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