เราควรจับjava.lang.Error
แอปพลิเคชันในสถานการณ์ใด
เราควรจับjava.lang.Error
แอปพลิเคชันในสถานการณ์ใด
คำตอบ:
โดยทั่วไปไม่เคย
อย่างไรก็ตามบางครั้งคุณต้องตรวจจับข้อผิดพลาดที่เฉพาะเจาะจง
หากคุณกำลังเขียนโค้ด framework-ish (กำลังโหลดคลาสของบุคคลที่สาม) คุณควรจับ LinkageError
(ไม่พบคลาส def ลิงค์ที่ไม่พอใจการเปลี่ยนคลาสที่เข้ากันไม่ได้)
ฉันยังเคยเห็นรหัสของบุคคลที่สามโง่ ๆ ที่ขว้างคลาสย่อยของ Error
ดังนั้นคุณจะต้องจัดการกับสิ่งเหล่านั้นด้วย
อย่างไรก็ตามฉันไม่แน่ใจว่าจะไม่สามารถกู้คืนOutOfMemoryError
ได้
ไม่เคย คุณไม่สามารถมั่นใจได้ว่าแอปพลิเคชันสามารถรันโค้ดบรรทัดถัดไปได้ ถ้าคุณได้รับOutOfMemoryError
คุณจะมีการรับประกันว่าคุณจะสามารถที่จะทำอะไรได้อย่างน่าเชื่อถือ จับ RuntimeException และตรวจสอบข้อยกเว้น แต่ไม่เคยมีข้อผิดพลาด
boolean assertionsEnabled = false; assert assertionsEnabled = true;
โดยทั่วไปคุณควรจับjava.lang.Error
และเขียนลงในบันทึกหรือแสดงให้ผู้ใช้เห็นเสมอ ฉันทำงานในฝ่ายสนับสนุนและเห็นทุกวันว่าโปรแกรมเมอร์ไม่สามารถบอกได้ว่าเกิดอะไรขึ้นในโปรแกรม
หากคุณมีเธรด daemon คุณต้องป้องกันไม่ให้ถูกยกเลิก ในกรณีอื่น ๆ แอปพลิเคชันของคุณจะทำงานได้อย่างถูกต้อง
คุณควรจับjava.lang.Error
ที่ระดับสูงสุดเท่านั้น
หากคุณดูรายการข้อผิดพลาดคุณจะเห็นว่าส่วนใหญ่สามารถจัดการได้ ตัวอย่างเช่นกZipError
เกิดขึ้นในการอ่านไฟล์ zip ที่เสียหาย
ข้อผิดพลาดที่พบบ่อยที่สุดคือOutOfMemoryError
และNoClassDefFoundError
ซึ่งในกรณีส่วนใหญ่ปัญหารันไทม์
ตัวอย่างเช่น:
int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];
สามารถผลิตไฟล์ OutOfMemoryError
แต่ปัญหารันไทม์และไม่มีเหตุผลที่จะยุติโปรแกรมของคุณ
NoClassDefFoundError
ส่วนใหญ่เกิดขึ้นหากไม่มีไลบรารีหรือถ้าคุณทำงานกับ Java เวอร์ชันอื่น หากเป็นส่วนเสริมของโปรแกรมคุณไม่ควรยุติโปรแกรมของคุณ
ฉันสามารถยกตัวอย่างได้อีกมากมายว่าเหตุใดจึงเป็นความคิดที่ดีที่จะตรวจสอบThrowable
ที่ระดับบนสุดและสร้างข้อความแสดงข้อผิดพลาดที่เป็นประโยชน์
OutOfMemoryError
ไม่ใช่ข้อผิดพลาดรันไทม์ไม่มีการรับประกันว่าแอปพลิเคชันจะสามารถกู้คืนได้ หากคุณโชคดีคุณอาจได้รับ OOM new byte[largeNumber]
แต่ถ้าการจัดสรรนั้นไม่เพียงพอที่จะทำให้เกิด OOM ก็อาจถูกทริกเกอร์ในบรรทัดถัดไปหรือเธรดถัดไป ปัญหานี้เป็นปัญหารันไทม์เพราะถ้าเป็นการป้อนข้อมูลที่ไม่น่าเชื่อถือก็ควรจะตรวจสอบก่อนที่จะเรียกlength
new byte[]
NoClassDefFoundError
สามารถเกิดขึ้นได้ทุกที่เนื่องจากมีการเรียกใช้เมื่อโค้ดจาวาที่คอมไพล์ไม่พบคลาส หาก JDK ของคุณกำหนดค่าไม่ถูกต้องอาจทำให้เกิดการพยายามใช้java.util.*
คลาสและแทบจะเป็นไปไม่ได้ที่จะตั้งโปรแกรมต่อต้าน หากคุณเป็นทางเลือกที่จะรวมการพึ่งพาคุณควรใช้ClassLoader
เพื่อตรวจสอบว่ามีอยู่หรือไม่ซึ่งเกิดClassNotFoundException
ขึ้น
ZipError
บ่งชี้ว่าไฟล์ jar ที่มีคลาสเป็นไฟล์ zip ที่เสียหาย นี่เป็นปัญหาที่ค่อนข้างร้ายแรงและ ณ จุดนี้คุณไม่สามารถเชื่อถือโค้ดใด ๆ ที่ถูกเรียกใช้งานได้และจะเป็นเรื่องที่ขาดความรับผิดชอบสำหรับการพยายาม "กู้คืน" จากโค้ด
java.lang.Error
หรือjava.lang.Throwable
อยู่ในระดับบนสุดอาจเป็นประโยชน์และพยายามทำอะไรบางอย่างกับมันเช่นบันทึกข้อความแสดงข้อผิดพลาด แต่ ณ จุดนั้นไม่มีการรับประกันว่าสิ่งนี้จะถูกดำเนินการ หาก JVM ของคุณเป็น OOMing การพยายามบันทึกอาจจัดสรรจำนวนมากขึ้นString
ซึ่งจะทริกเกอร์ OOM อื่น
ในสภาพแวดล้อมแบบมัลติเธรดคุณมักต้องการจับมัน! เมื่อคุณจับได้ให้เข้าสู่ระบบและยุติแอปพลิเคชันทั้งหมด! หากคุณไม่ทำเช่นนั้นเธรดบางส่วนที่อาจทำส่วนสำคัญบางอย่างจะตายไปและแอปพลิเคชันที่เหลือจะคิดว่าทุกอย่างเป็นปกติ จากนั้นสถานการณ์ที่ไม่พึงประสงค์มากมายสามารถเกิดขึ้นได้ ปัญหาที่เล็กที่สุดอย่างหนึ่งคือคุณจะไม่สามารถค้นหาต้นตอของปัญหาได้อย่างง่ายดายหากเธรดอื่นเริ่มทิ้งข้อยกเว้นบางอย่างเนื่องจากเธรดหนึ่งไม่ทำงาน
ตัวอย่างเช่นโดยปกติการวนซ้ำควรเป็น:
try {
while (shouldRun()) {
doSomething();
}
}
catch (Throwable t) {
log(t);
stop();
System.exit(1);
}
แม้ว่าในบางกรณีคุณจะต้องการจัดการข้อผิดพลาดที่แตกต่างกันออกไปเช่นใน OutOfMemoryError คุณจะสามารถปิดแอปพลิเคชันได้เป็นประจำ (แม้อาจจะทำให้หน่วยความจำว่างและดำเนินการต่อ) ในบางกรณีคุณก็ไม่สามารถทำได้มากนัก
OutOfMemoryError
และต่อเนื่องมากกว่าที่มีอยู่ทันทีเป็นเรื่องโง่เพราะโปรแกรมของคุณนั้นอยู่ในสภาพที่ไม่ได้กำหนด
น้อยครั้งมาก
ฉันจะพูดเฉพาะที่ระดับบนสุดของเธรดเพื่อให้ ATTEMPT ส่งข้อความพร้อมเหตุผลที่เธรดกำลังจะตาย
หากคุณอยู่ในกรอบที่ทำสิ่งนี้ให้คุณปล่อยให้มันอยู่ในกรอบ
แทบจะไม่เคย. ข้อผิดพลาดได้รับการออกแบบให้เป็นปัญหาที่โดยทั่วไปแอปพลิเคชันไม่สามารถทำอะไรได้ ข้อยกเว้นเพียงอย่างเดียวคือการจัดการกับการนำเสนอข้อผิดพลาด แต่อาจไม่เป็นไปตามแผนที่วางไว้ขึ้นอยู่กับข้อผิดพลาด
โดยError
ปกติแล้วไม่ควรถูกจับเนื่องจากบ่งบอกถึงภาวะผิดปกติที่ไม่ควรเกิดขึ้นบ่งชี้ว่าสภาพผิดปกติที่ไม่ควรเกิดขึ้น
จากข้อกำหนด Java API สำหรับError
คลาส:
An
Error
เป็นคลาสย่อยThrowable
ที่บ่งบอกถึงปัญหาร้ายแรงที่แอปพลิเคชันที่สมเหตุสมผลไม่ควรพยายามจับ ข้อผิดพลาดดังกล่าวส่วนใหญ่เป็นภาวะผิดปกติ [ ... ]ไม่จำเป็นต้องใช้เมธอดในการประกาศในส่วนของการพ่นข้อผิดพลาดคลาสย่อยใด ๆ ที่อาจเกิดขึ้นระหว่างการดำเนินการของเมธอด แต่ไม่ถูกจับเนื่องจากข้อผิดพลาดเหล่านี้เป็นเงื่อนไขผิดปกติที่ไม่ควรเกิดขึ้น
ตามที่ระบุไว้ an Error
จะถูกโยนในสถานการณ์ที่เป็นโอกาสเท่านั้นเมื่อError
เกิดขึ้นมีแอปพลิเคชันน้อยมากที่สามารถทำได้และในบางสถานการณ์ Java Virtual Machine เองอาจอยู่ในสถานะที่ไม่เสถียร (เช่นVirtualMachineError
)
แม้ว่า an Error
จะเป็นคลาสย่อยThrowable
ซึ่งหมายความว่าสามารถจับได้โดยtry-catch
อนุประโยค แต่ก็อาจไม่จำเป็นจริงๆเนื่องจากแอปพลิเคชันจะอยู่ในสถานะผิดปกติเมื่อError
JVM ถูกโยนทิ้ง
นอกจากนี้ยังมีส่วนสั้น ๆ ในหัวข้อนี้ในมาตรา11.5 ยกเว้นลำดับชั้นของJava Language ข้อกำหนดฉบับที่
หากคุณบ้าพอที่จะสร้างกรอบการทดสอบหน่วยใหม่นักวิ่งทดสอบของคุณอาจต้องจับ java.lang.AssertionError ที่เกิดจากกรณีทดสอบใด ๆ
มิฉะนั้นให้ดูคำตอบอื่น ๆ
และยังมีอีกสองกรณีที่หากคุณพบข้อผิดพลาดคุณจะต้องทำการแก้ไขใหม่ ตัวอย่างเช่นไม่ควรจับThreadDeathอาจทำให้เกิดปัญหาใหญ่ได้คือคุณจับมันในสภาพแวดล้อมที่มีอยู่ (เช่นแอปพลิเคชันเซิร์ฟเวอร์):
แอปพลิเคชันควรจับอินสแตนซ์ของคลาสนี้เฉพาะในกรณีที่ต้องล้างข้อมูลหลังจากถูกยกเลิกแบบอะซิงโครนัส หาก ThreadDeath ถูกจับโดยวิธีการเป็นสิ่งสำคัญที่จะต้องมีการเปลี่ยนใหม่เพื่อให้เธรดตายจริง
Error
s
มากน้อยมาก
ฉันทำสำหรับกรณีที่รู้จักกันเฉพาะเจาะจงมากเพียงกรณีเดียว ตัวอย่างเช่น java.lang.Uns พอใจLinkErrorสามารถโยนได้หากClassLoaderสองตัวโหลด DLL เดียวกัน (ฉันยอมรับว่าฉันควรย้าย JAR ไปยัง classloader ที่ใช้ร่วมกัน)
แต่กรณีที่พบบ่อยที่สุดคือคุณต้องเข้าสู่ระบบเพื่อให้ทราบว่าเกิดอะไรขึ้นเมื่อผู้ใช้ร้องเรียน คุณต้องการข้อความหรือป๊อปอัปไปยังผู้ใช้ แต่จากนั้นก็เงียบหายไป
แม้แต่โปรแกรมเมอร์ใน C / C ++ พวกเขาก็แสดงข้อผิดพลาดและบอกสิ่งที่คนไม่เข้าใจก่อนที่จะออก (เช่นหน่วยความจำล้มเหลว)
ในการประยุกต์ใช้ Android ฉันกำลังจับjava.lang.VerifyError ไลบรารีที่ฉันใช้จะไม่ทำงานในอุปกรณ์ที่มีระบบปฏิบัติการเวอร์ชันเก่าและรหัสไลบรารีจะทำให้เกิดข้อผิดพลาดดังกล่าว แน่นอนว่าฉันสามารถหลีกเลี่ยงข้อผิดพลาดได้โดยการตรวจสอบเวอร์ชันของระบบปฏิบัติการที่รันไทม์ แต่:
ตามหลักการแล้วเราไม่ควรจัดการ / จับข้อผิดพลาด แต่อาจมีบางกรณีที่เราจำเป็นต้องทำตามข้อกำหนดของเฟรมเวิร์กหรือแอปพลิเคชัน สมมติว่าฉันมี XML Parser daemon ซึ่งใช้DOM Parserซึ่งใช้หน่วยความจำมากกว่า หากมีข้อกำหนดเช่น Parser thread ไม่ควรตายเมื่อได้รับOutOfMemoryErrorควรจัดการและส่งข้อความ / เมลไปยังผู้ดูแลระบบแอปพลิเคชัน / เฟรมเวิร์ก
โดยหลักการแล้วเราไม่ควรตรวจจับ Error ในแอปพลิเคชัน Java ของเราเนื่องจากเป็นอาการผิดปกติ แอปพลิเคชั่นจะอยู่ในสถานะผิดปกติและอาจส่งผลให้เกิดอาการคันหรือให้ผลลัพธ์ที่ผิดพลาดอย่างร้ายแรง
อาจเป็นการเหมาะสมที่จะตรวจจับข้อผิดพลาดภายในการทดสอบหน่วยที่ตรวจสอบการยืนยัน หากมีคนปิดใช้งานการยืนยันหรือลบการยืนยันที่คุณต้องการทราบ
มีข้อผิดพลาดเมื่อ JVM ไม่ทำงานตามที่คาดไว้อีกต่อไปหรือใกล้จะถึงแล้ว หากคุณตรวจพบข้อผิดพลาดไม่มีการรับประกันว่าบล็อกจับจะทำงานและแม้แต่น้อยกว่าที่จะทำงานจนจบ
นอกจากนี้ยังขึ้นอยู่กับคอมพิวเตอร์ที่ใช้งานสถานะหน่วยความจำปัจจุบันดังนั้นจึงไม่มีวิธีทดสอบพยายามทำให้ดีที่สุด คุณจะได้ผลลัพธ์ที่ไม่เป็นธรรม
คุณจะปรับลดระดับความสามารถในการอ่านโค้ดของคุณด้วย