ทิ้งข้อยกเว้นรันไทม์ในแอปพลิเคชัน Java


12

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

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

จำเป็นต้องมีข้อยกเว้นที่ไม่ จำกัด ในแอปพลิเคชันธุรกิจอย่างไร

จากประสบการณ์ของฉันในอดีตเกี่ยวกับข้อยกเว้นรันไทม์:

1) ข้อยกเว้นที่ไม่ได้ตรวจสอบทำให้โค้ดไม่สามารถคาดเดาได้เพราะจะไม่แสดงแม้แต่ใน Javadoc

2) การโยนข้อยกเว้นที่ไม่ได้ตรวจสอบในแอปพลิเคชันทางธุรกิจนั้นไม่มีความหมายเพราะเมื่อคุณโยนทิ้งและมันตรงไปที่ใบหน้าของผู้ใช้คุณจะอธิบายให้ผู้ใช้ทราบได้อย่างไร ฉันเคยเห็นเว็บแอปพลิเคชันเพียงพอซึ่งแสดง500 -Internal Error. Contact Administratorว่าไม่มีความหมายสำหรับผู้ใช้หรือทีมสนับสนุนที่จัดการแอปพลิเคชัน

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


คุณช่วยอธิบาย Service Tier ได้อย่างไร เลเยอร์อยู่ไกลที่สุดจากผู้ใช้หรือใกล้กับผู้ใช้มากที่สุด
Manoj R

ทำไมคำถามนี้ไม่เหมาะกับ SO
Bjarke Freund-Hansen

@Manoj R: ทั้งคู่ ระดับบริการหรือเลเยอร์เป็นที่ซึ่งกฎและตรรกะทางธุรกิจถูกแยกออกจากทั้งรายละเอียดของเทคโนโลยี DB และการนำเสนอลูกค้า
Michael Borgwardt

6
ข้อยกเว้นที่ไม่ได้ตรวจสอบ [... ] จะไม่ปรากฏแม้แต่ใน Javadoc => พวกเขาจะปรากฏขึ้นหากคุณจัดทำเอกสารด้วย@throwsแท็กซึ่งเป็นวิธีปฏิบัติที่ดี
assylias

4
@SureshKoya Effective Java รายการ 62: บันทึกข้อยกเว้นทั้งหมดที่ส่งออกโดยแต่ละวิธี คลายบีบอัด@throws
assylias

คำตอบ:


13

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

สำหรับคะแนนของคุณ:

1) ข้อยกเว้นการยืมทำให้สกปรกรหัสและไม่มีการคาดเดาไม่ได้น้อยลงเพราะพวกเขาแสดงทุกที่

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

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

มีข้อยกเว้นสองประเภท: สิ่งที่เกิดขึ้น "ตามปกติ" และโดยทั่วไปแล้วจะได้รับการจัดการอย่างใกล้ชิดกับสิ่งที่เกิดขึ้นและสิ่งที่ยอดเยี่ยมและสามารถจัดการได้โดยทั่วไปในชั้นที่สูงมาก (เพียงยกเลิกการกระทำปัจจุบันและบันทึก / แสดงข้อผิดพลาด)

การตรวจสอบข้อยกเว้นเป็นการพยายามแยกความแตกต่างนี้ในไวยากรณ์ภาษา ณ จุดที่มีการกำหนดข้อยกเว้น ปัญหาเกี่ยวกับสิ่งนี้คือ

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

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

2
@Suresh Koya: ไม่ฉันหมายถึงลำดับชั้นความจริงที่ว่าการประกาศSQLException extends Exceptionหมายถึงการเลือกที่จะโยนSQLExceptionเพราะข้อผิดพลาดเกี่ยวกับการเข้าถึงฐานข้อมูลโดยอัตโนมัติหมายถึงการตรวจสอบข้อยกเว้น และคุณสามารถบันทึกข้อยกเว้นที่ไม่ จำกัด ในข้อคิดเห็น Javadoc ได้ดี ทำงานได้ดีสำหรับภาษาอื่น ๆ ทั้งหมด
Michael Borgwardt

1
@MichaelBorgwardt "ข้อยกเว้นที่ตรวจสอบแล้วมีความล้มเหลวในการออกแบบภาษา" เป็นความเห็นส่วนตัวของคุณหรือไม่ถ้าไม่ฉันต้องการอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ ลิงก์ที่แท้จริงจะช่วยได้มาก
Vipin

2
@Vipin: มันเป็นความเห็นส่วนตัวของฉัน แต่เป็นสิ่งที่คนอื่น ๆ แบ่งปันเช่น Bruce Eckel: mindview.net/Etc/Discussions/CheckedExceptions - และความจริงที่ว่าไม่มีภาษาอื่น ๆ ที่ใช้ข้อยกเว้นการตรวจสอบใน 20 ปีนับตั้งแต่ Java ถูกนำมาพูด สำหรับตัวเอง ...
Michael Borgwardt

2

มุมมองของฉันคือสิ่งที่ประเภทของข้อยกเว้นโยนขึ้นอยู่กับสิ่งที่รหัสของคุณกำลังทำ

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

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

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

ฉันเดาว่าปรัชญาที่คุณพูดถึงมาจากหนึ่งในสองแหล่ง:

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

หากบางสิ่งบางอย่างอาจเกิดขึ้นบ่อยครั้งก็ไม่ใช่ข้อยกเว้น แต่ตกลงว่าไม่ควรโยนข้อผิดพลาดซึ่งผู้ใช้ไม่มีเงื่อนงำ
Manoj R

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

นอกจากนี้แม้ว่าจะมีการโยนข้อยกเว้นรันไทม์ฉันชอบอนุสัญญา @assylias ที่ชี้ไป
randominstanceOfLivingThing

1

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

และเมื่อคุณอ่านล็อกไฟล์ของระบบ J2EE บางครั้งเช่นการติดตั้ง SAP NetWeaver คุณจะเห็นว่ามีข้อยกเว้นเกิดขึ้นตลอดเวลา


จากข้อกำหนดภาษาจาวา: "คลาสข้อยกเว้นรันไทม์ (RuntimeException และคลาสย่อย) ได้รับการยกเว้นจากการตรวจสอบเวลาคอมไพล์เนื่องจากในการตัดสินของผู้ออกแบบภาษาการเขียนโปรแกรม Java การประกาศข้อยกเว้นดังกล่าวจะไม่ช่วยในการสร้างความถูกต้อง ของโปรแกรมการดำเนินการหลายอย่างและโครงสร้างของภาษาการเขียนโปรแกรม Java อาจส่งผลให้เกิดข้อยกเว้นแบบรันไทม์ "
randominstanceOfLivingThing

1
ข้อยกเว้นรันไทม์ที่คุณกำลังพูดถึงคือข้อผิดพลาดที่เกิดขึ้นจาก Java เนื่องจากระบบรันไทม์ของ Java ไม่มีข้อมูลว่าทำไมคุณจึงพยายามโทรออกโดยเฉพาะ เช่น: NullPointerException จะเกิดขึ้นหากคุณเรียกใช้เมธอดที่เป็นโมฆะ ในกรณีนั้นระบบ Java runtime ไม่มีคำที่ถูกต้องสำหรับโปรแกรมเมอร์ที่โง่เขลาและจะตบผู้โทรด้วย NullPointerException ส่วนที่น่าเศร้าคือผู้โทรได้ขายผลิตภัณฑ์ Netweaver ให้คุณและคุณในฐานะผู้ใช้ตอนนี้ตกเป็นเหยื่อของการเขียนโปรแกรมที่ไม่ดี ผู้ทดสอบจะถูกตำหนิอย่างเท่าเทียมกันเนื่องจากพวกเขาไม่ได้ทำการทดสอบขอบเขตทั้งหมด
randominstanceOfLivingThing

1

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

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

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

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

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

วิธีหนึ่งในการจัดการข้อยกเว้นคือการโยนข้อยกเว้นอื่นที่ให้คำอธิบายปัญหาในระดับที่สูงขึ้น (เช่น“ failed to initialize” แทนที่จะเป็น“ index out of bounds”) นี่เป็นรูปแบบที่ดีตราบใดที่คุณไม่สูญเสียข้อมูลเกี่ยวกับสาเหตุของข้อยกเว้น ใช้ข้อยกเว้นโดยละเอียดเพื่อเริ่มต้นcauseข้อยกเว้นระดับสูงกว่าหรือบันทึกรายละเอียด (ดังที่อธิบายไว้ข้างต้น) การบันทึกมีความเหมาะสมที่สุดเมื่อคุณกำลังจะข้ามขอบเขตระหว่างกระบวนการเช่นการโทร IPC เนื่องจากไม่มีการรับประกันว่าจะมีคลาสข้อยกเว้นระดับต่ำในปลายอีกด้านหนึ่งของการเชื่อมต่อ การรักษาเป็นสาเหตุที่แนบมาเหมาะสมที่สุดเมื่อข้ามขอบเขตภายใน

อีกรูปแบบที่คุณเห็นคือแบบ catch-and-release:

try {
    // ...
} catch (FooException e) {
    throw e;
}

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

ไม่มีความแตกต่างที่แท้จริงระหว่างข้อยกเว้นที่ตรวจสอบและไม่ได้ตรวจสอบอย่างอื่นนอกเหนือจากความจริงที่ว่าคุณต้องประกาศข้อยกเว้นที่ตรวจสอบแล้วซึ่งมีขอบเขตข้ามวิธีการ ยังคงเป็นความคิดที่ดีที่จะบันทึกข้อยกเว้นที่ไม่ได้ตรวจสอบ (ด้วย@throwsความคิดเห็น javadoc) หากคุณรู้ว่ารหัสเหล่านั้นถูกโยนโดยเจตนา อย่าจงใจโยนjava.lang.Errorหรือคลาสย่อยของมัน (เว้นแต่ว่าคุณกำลังเขียนการใช้งาน JVM)

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


0

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

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

หากแอปของคุณโหลดข้อมูลจากไฟล์หรือฐานข้อมูล จากนั้น ..

try {
  File data = new File(...);
  // parse file here
} catch (Exception ex) {
  throw new MissingDataFileException("data file not found");
}

ผู้เรียกสามารถตรวจพบ MissingDataFileException ที่เลือกอยู่เสมอแล้วลองโหลดข้อมูลจากฐานข้อมูล

try {
  Connection con = DriverManager.getConnection( host, username, password );
  // query data here
} catch (Exception ex) {
  throw new RuntimeException("better call Saul!");
}

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