ไม่ใช่วิธีปฏิบัติที่ดีในการจัดการข้อยกเว้นรันไทม์ในรหัสหรือไม่


11

ฉันกำลังทำงานกับแอปพลิเคชัน Java และฉันเห็นว่ามีการจัดการข้อยกเว้นเวลาทำงานในหลาย ๆ ที่ ตัวอย่างเช่น,

try {
    // do something
} catch(NullPointerException e) {
    return null;
}

คำถามของฉันคือเมื่อใดที่ควรปฏิบัติกับข้อยกเว้นรันไทม์ เมื่อใดควรยกเว้นข้อยกเว้นที่ไม่ถูกจัดการ?


7
-1: ไม่มีคำตอบเดียวสำหรับคำถามที่กว้างและคลุมเครือ เป็นไปไม่ได้ที่จะให้คำตอบเดียวสำหรับคำถามที่ไม่ได้เน้นเช่นนี้ คำถามนี้แย่มาก โปรดระบุตัวอย่างที่คุณสงสัย
S.Lott

@ S.Lott ฉันไม่เห็นด้วยในกรณีนี้เนื่องจากดูเหมือนว่ามีโปรแกรมเมอร์บางส่วนที่อยู่ในหัวของพวกเขาว่านี่เป็นกรณีที่ไม่มีเหตุผล "ดี"
SoylentGray

2
@Chad: "นี่เป็นกรณีที่ไม่มี" ดี "Rationality" นั่นอาจเป็นจริง แต่คำตอบเดียวที่เป็นไปได้คือต้อง "ขึ้นอยู่กับ" ดังนั้นคำถามดูเหมือนจะผิดพลาด
S.Lott

คำตอบ:


18

มันขึ้นอยู่กับ.

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


2
ฉันเห็นด้วยกับ "มันขึ้นอยู่กับ" แต่ตัวอย่างการแยกวิเคราะห์ของคุณดูเหมือนจะเป็นกรณีของการออกแบบ API ที่ไม่ดี Integer#parseIntควรส่งคืนMaybe<Integer>แทนและไม่โยนข้อยกเว้นใด ๆ
Jörg W Mittag

3
@ Jörg W Mittag: ฉันยอมรับว่ามันเป็นการออกแบบ API ที่ไม่ดี แต่มันเป็นโลกแห่งความจริงที่เราต้องจัดการ วิธีจัดการกับค่าที่โยนได้ / ผลตอบแทนขึ้นอยู่กับว่าโลกใช้งานได้จริงอย่างไรไม่ใช่วิธีที่มันควรจะทำงานได้อย่างเหมาะสม:-)
Joonas Pulakka

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

7

NullPointerExceptions มักจะเป็นสัญญาณของการตรวจสอบโมฆะที่ขาดหายไป ดังนั้นแทนที่จะจับมันแบบนี้คุณควรเพิ่มการตรวจสอบค่าโมฆะ apropriate เพื่อให้แน่ใจว่าไม่ได้โยนข้อยกเว้น

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

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


1
ฉันต้องการเพิ่มว่าการตรวจสอบค่า Null เป็นการตัดสินใจที่ดีกว่า
Mahmoud Hossam

... ถึงกระนั้นหากคุณทำการจัดสรรหลายสิบครั้งที่ "ไม่ควรพลาด" รอบ ๆ สถานที่เดียวการเพิ่มการตรวจสอบ null สำหรับแต่ละรายการอาจทำให้รหัสดูน่าขัน ข้อยกเว้น catch-all (ที่จะจัดการกับสถานการณ์อย่างสง่างามไม่ใช่เฉพาะreturn null;) จะเป็นทางออกที่ดีกว่า
เอสเอฟ

คุณอาจสับสนกับ Java อย่างอื่น (C ++ สำหรับตัวอย่าง) เมื่อการจัดสรรล้มเหลวคุณจะได้รับ OutOfMemoryError หรือสิ่งที่คล้ายกันไม่เคยเป็นตัวชี้โมฆะ การส่งคืนค่า null แทนข้อยกเว้นคือการวางข้อผิดพลาดเพื่อรอให้โค้ดระเบิดที่อื่น
deadalnix

newพ่นstd::bad_allocใน C ++
R. Martinho Fernandes

สมมติว่าผู้ประกอบการใหม่ไม่ได้บรรทุกมากเกินไปซึ่งเป็นเรื่องธรรมดา ใน C ++ ทุกอย่างสามารถเกิดขึ้นได้) แต่ก็โอเคสมมุติว่า malloc ของ C จุดสำคัญคือคุณไม่เคยได้รับสิ่งนี้ในภาษาจาวา
deadalnix

4

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


2

ข้อยกเว้นควรเป็นเพียงแค่นั้น .. ข้อยกเว้น แนวทางปฏิบัติที่ดีที่สุดเมื่อใช้ข้อยกเว้นคือให้ใช้เพื่อครอบคลุมสถานการณ์ที่มีสิ่งที่ตรงกันข้ามกับสิ่งที่คุณคาดหวังว่าจะเกิดขึ้น ตัวอย่างคลาสสิกคือ FileNotFoundException ซึ่งถูกส่งออกไปเมื่อไม่มีไฟล์อยู่ที่นั่น หากคุณกำลังทดสอบการมีอยู่ของไฟล์คุณควรใช้ File.exists () เนื่องจากคุณเพียงแค่ใช้ไม้เท้า 10 ฟุตเพื่อดูว่าคุณมีอะไรกระทบหรือไม่

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

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

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

Integer getUserCount() {
   Integer result = null;
   try {
      // Attempt to open database and retrieve data
   } catch (TimeoutException e) {
      logger.error("Got a watch?");
   } catch (MissingDatabaseException e) {
      logger.error("What are you smoking?");
   } catch (PermissionsToReadException e) {
      logger.error("Did you *really* think you were getting away with that?");
   } catch (PressedSendButtonToHardException e) {
      logger.error("Seriously.. just back away from the computer... slowly..");
   } catch (WTFException e) {
      logger.error("You're on your own with this one.. I don't even know what happened..");
   } finally {
      // Close connections and whatnot
   }
   return result;
}

void doStuff() {
   Integer result = getUserCount();
   if(result != null) {
       // Went as planned..
   }
}

6
หากคุณใช้ File.exists () และพึ่งพาผลลัพธ์สภาพการแข่งขันอาจเกิดขึ้นหากไฟล์ถูกลบระหว่าง File.exists () และ File.open () หากสิ่งนี้ทริกเกอร์ข้อผิดพลาดด้านความปลอดภัยผู้โจมตีอาจทำให้เกิดเงื่อนไขนี้ได้ตามวัตถุประสงค์ ด้วยเหตุนี้บางครั้งการทำปฎิบัติการอะตอมจึงดีกว่าคือลองใช้งานและตรวจจับข้อยกเว้น
281377

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

นี่เป็นการตัดสินใจที่ผิดพลาดในการส่งคืน null มันจะส่งผลให้ใน NullPointerException ในบางจุดและจะยากมากที่จะแก้ปัญหาสิ่งที่ผิดพลาด เพราะบางคนจะลืมตรวจสอบในบางจุด
deadalnix

@deadalnix: ฉันสามารถโต้แย้งได้ว่าคุณสามารถลืมได้อย่างง่ายดายเช่นเดียวกับการพยายามจับอย่างอื่น ความแตกต่างเป็นเรื่องของสไตล์ไม่ใช่ฟังก์ชั่น
Neil

@ammoQ: ฉันไม่เห็นด้วย ฉันคิดว่าคุณควรใช้ File.exists () และภายใต้สถานการณ์ที่หายากว่ามันจะถูกลบออกก่อนที่คุณจะใช้มันยกเว้นมีความเหมาะสมมากกว่า ความแตกต่างคือที่ที่คุณจับได้ เพียงมีตัวดักจับข้อยกเว้นแบบครอบคลุมสำหรับข้อผิดพลาดที่ไม่คาดคิดเพื่อบันทึกและรายงาน
Neil

-5

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


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