ให้พิจารณาสถานการณ์ที่คุณมีรหัสที่ให้:
public void delete() throws IOException, SQLException { // Non-Compliant
/* ... */
}
อันตรายที่นี่คือรหัสที่คุณเขียนเพื่อโทรdelete()
จะมีลักษณะดังนี้:
try {
foo.delete()
} catch (Exception e) {
/* ... */
}
มันก็ไม่ดีเหมือนกัน และจะถูกจับด้วยกฎอื่นที่จับค่าสถานะการยกเว้นคลาสพื้นฐาน
กุญแจสำคัญคือการไม่เขียนโค้ดที่ทำให้คุณต้องการเขียนโค้ดไม่ดีที่อื่น
กฎที่คุณพบเป็นกฎที่ค่อนข้างใช้กันทั่วไป Checkstyleมีกฎการออกแบบ:
ThrowsCount
จำกัด การโยนข้อความสั่งให้นับที่ระบุ (1 โดยค่าเริ่มต้น)
เหตุผล: ข้อยกเว้นเป็นส่วนหนึ่งของส่วนต่อประสานของวิธีการ การประกาศวิธีการโยนข้อยกเว้นที่รูทแตกต่างกันมากเกินไปทำให้เกิดข้อยกเว้นในการจัดการที่ยากลำบากและนำไปสู่แนวทางการเขียนโปรแกรมที่ไม่ดีเช่นการเขียนโค้ดเช่น catch (Exception ex) การตรวจสอบนี้บังคับให้นักพัฒนาวางข้อยกเว้นลงในลำดับชั้นซึ่งในกรณีที่ง่ายที่สุดผู้เรียกต้องตรวจสอบข้อยกเว้นเพียงประเภทเดียว แต่ผู้เรียนสามารถจับคลาสย่อยใด ๆ ได้หากจำเป็น
สิ่งนี้อธิบายปัญหาได้อย่างแม่นยำและปัญหาคืออะไรและทำไมคุณไม่ควรทำ เป็นมาตรฐานที่ได้รับการยอมรับเป็นอย่างดีว่าเครื่องมือวิเคราะห์แบบคงที่จำนวนมากจะระบุและตั้งค่าสถานะ
และในขณะที่คุณอาจทำตามการออกแบบภาษาและอาจมีบางครั้งที่มันเป็นสิ่งที่ถูกต้องที่จะทำมันเป็นสิ่งที่คุณควรเห็นและไปทันที "อืมทำไมฉันถึงทำอย่างนี้?" อาจเป็นที่ยอมรับได้สำหรับรหัสภายในที่ทุกคนได้รับการลงโทษทางวินัยมากพอที่จะไม่ทำcatch (Exception e) {}
แต่บ่อยครั้งที่ฉันไม่เห็นคนถูกตัดมุมโดยเฉพาะในสถานการณ์ภายใน
อย่าทำให้คนที่ใช้คลาสของคุณต้องการเขียนโค้ดที่ไม่ดี
ฉันควรชี้ให้เห็นว่าความสำคัญของสิ่งนี้ลดลงด้วย Java SE 7 และหลังจากนั้นเนื่องจากคำสั่ง catch เดี่ยวสามารถตรวจจับข้อยกเว้นหลาย ๆ ข้อได้ (การตรวจจับชนิดข้อยกเว้นหลายรายการและข้อยกเว้น Rethrowing ด้วยการปรับปรุงการตรวจสอบประเภทจาก Oracle)
ด้วย Java 6 และก่อนหน้านี้คุณจะมีโค้ดที่ดูเหมือน:
public void delete() throws IOException, SQLException {
/* ... */
}
และ
try {
foo.delete()
} catch (IOException ex) {
logger.log(ex);
throw ex;
} catch (SQLException ex) {
logger.log(ex);
throw ex;
}
หรือ
try {
foo.delete()
} catch (Exception ex) {
logger.log(ex);
throw ex;
}
ตัวเลือกเหล่านี้กับ Java 6 ไม่เหมาะอย่างยิ่ง วิธีแรกละเมิดแห้ง บล็อกจำนวนมากทำสิ่งเดียวกันซ้ำแล้วซ้ำอีก - ครั้งเดียวสำหรับแต่ละข้อยกเว้น คุณต้องการที่จะเข้าสู่ระบบข้อยกเว้นและ rethrow มันได้หรือไม่ ตกลง. บรรทัดของรหัสเดียวกันสำหรับแต่ละข้อยกเว้น
ตัวเลือกที่สองนั้นแย่กว่าด้วยเหตุผลหลายประการ ครั้งแรกมันหมายความว่าคุณกำลังจับข้อยกเว้นทั้งหมด ตัวชี้ Null ติดอยู่ที่นั่น (และไม่ควร) นอกจากนี้คุณจะ rethrowing Exception
ซึ่งหมายความว่าลายเซ็นวิธีจะเป็นdeleteSomething() throws Exception
ซึ่งก็ทำให้เป็นระเบียบเพิ่มเติมขึ้นสแต็คเป็นคนที่ใช้รหัสของคุณตอนนี้บังคับให้catch(Exception e)
ไป
ด้วย Java 7 สิ่งนี้ไม่สำคัญเท่ากับคุณทำได้:
catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
นอกจากนี้ประเภทการตรวจสอบถ้าไม่จับประเภทของข้อยกเว้นที่ถูกโยน:
public void rethrowException(String exceptionName)
throws IOException, SQLException {
try {
foo.delete();
} catch (Exception e) {
throw e;
}
}
ตัวตรวจสอบชนิดจะรู้ว่าe
อาจเพียง แต่จะเป็นประเภทหรือIOException
SQLException
ฉันยังคงไม่กระตือรือร้นมากเกินไปเกี่ยวกับการใช้งานสไตล์นี้ แต่มันไม่ได้ทำให้เกิดรหัสที่ไม่ดีอย่างที่มันเป็นภายใต้ Java 6 (ซึ่งมันจะบังคับให้คุณมีลายเซ็นวิธีการเป็น superclass ที่ข้อยกเว้นขยาย)
แม้จะมีการเปลี่ยนแปลงเหล่านี้ แต่เครื่องมือการวิเคราะห์แบบสแตติกจำนวนมาก (Sonar, PMD, Checkstyle) ยังคงบังคับใช้คำแนะนำสไตล์ Java 6 มันไม่ใช่เรื่องเลวร้าย ฉันมักจะเห็นด้วยกับคำเตือนเหล่านี้ว่าจะยังคงมีการบังคับใช้ แต่คุณอาจเปลี่ยนลำดับความสำคัญเป็นหลักหรือรองตามวิธีที่ทีมของคุณจัดลำดับความสำคัญ
หากข้อยกเว้นควรจะตรวจสอบหรือไม่ถูกตรวจสอบ ... นั่นคือเรื่องของการกรัมR e เสื้อ อภิปรายที่หนึ่งสามารถหาบล็อกโพสต์ที่นับไม่ถ้วนการขึ้นแต่ละด้านของการโต้แย้ง อย่างไรก็ตามหากคุณทำงานกับข้อยกเว้นที่ตรวจสอบแล้วคุณควรหลีกเลี่ยงการโยนหลายประเภทอย่างน้อยภายใต้ Java 6