วิธีจัดการกับข้อยกเว้นที่ตรวจสอบซึ่งไม่สามารถโยนได้


35

ตัวอย่าง:

foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");

เนื่องจากการเข้ารหัสเป็น hardcoded และถูกต้องตัวสร้างจะไม่โยน UnsupportedEncodingException ที่ประกาศในสเปค (ยกเว้นกรณีที่จาวาใช้งานไม่ได้ซึ่งในกรณีนี้ฉันหลงทางอยู่แล้ว) อย่างไรก็ตาม Java บังคับให้ฉันจัดการกับข้อยกเว้นนั้นอยู่ดี

ปัจจุบันดูเหมือนว่า

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
}
catch(UnsupportedEncodingException e) { /* won't ever happen */ }

ความคิดใดจะทำให้ดีขึ้นได้อย่างไร


4
สำหรับความท้าทายที่แท้จริงให้เขียนการทดสอบหน่วยเพื่อให้แน่ใจว่าการจับนี้ใช้งานได้จริง
Jay Elston

1
`โยน ImpossibleException ใหม่ (" รีบูตจักรวาลสิ่งต่าง ๆ เกิดขึ้น ", e);
Chris Cudmore

1
"จะไม่เกิดขึ้น" จะ ...

Thorbjørn Ravn Andersen: มันอาจหลังจากเปลี่ยนโปรแกรม แต่อย่างน้อยก็อยู่ในสถานะปัจจุบันไม่มีข้อมูลอินพุตชุดใดที่สามารถทริกเกอร์ข้อยกเว้นได้
281377

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

คำตอบ:


27

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


ความคิดที่ดี; ง่ายassert false;ไม่เพิ่มความยุ่งเหยิงมากเกินไปและทำให้ชัดเจนว่าฉันคิดว่าจะไม่มีการป้อนบล็อก catch
281377

5
@ammoQ assert false : "should never happen"หรือคุณยังสามารถเพิ่มข้อความที่จะทำให้เจตนาของคุณอย่างชัดเจน:
PéterTörök

13
ยิ่งไปกว่านั้น "ไม่ควรเกิดขึ้นเพราะ Java ต้องการชุดรองรับ ISO-8859-1 เพื่อ charset"
dan04

3
assertเปิดใช้งานการยืนยันความหมาย ฉันโยนUnexpectedException(ซึ่งยังมีประโยชน์ในการให้ฉันมีกองติดตาม ... )
Chop

35

ถ้าฉันได้รับค่าร้อยละสำหรับทุกครั้งที่ฉันเห็นบันทึก / ข้อผิดพลาด "สิ่งนี้ไม่ควรเกิดขึ้น" ฉันจะ ... ดีสองเซ็นต์ แต่ยังคง...

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

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


28

ฉันทำแบบนี้มาตลอด:

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
} catch(UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

อาจเป็น verbose เล็กน้อย (Java คือ ... ) แต่อย่างน้อยคุณจะได้รับข้อผิดพลาดในการยืนยันเมื่อสิ่งที่เป็นไปไม่ได้เกิดขึ้น

หากการติดตั้ง Java ใช้งานไม่ได้คุณจะต้องได้รับข้อความแสดงข้อผิดพลาดที่ดีที่สุดโดยเร็วที่สุดแทนการเพิกเฉยต่อสิ่งที่เป็นไปไม่ได้ และแม้ว่าการใช้งานจาวาจะไม่เสียหายใครบางคนสามารถเปลี่ยนรหัสของคุณเป็น"UTF8"(อุ๊ปส์ - ควรเป็น"UTF-8"อย่างไร)

สิ่งนี้ควรเป็นข้อยกเว้นแบบรันไทม์ในตอนแรก JDK เต็มไปด้วยตัวเลือกที่ผิดประเภทนี้


4
การแยกไม่ถูกต้องจริง (หรือละเว้นถ้าคุณต้องการ) คือไม่มีอินสแตนซ์ Charset ที่กำหนดไว้ล่วงหน้าสำหรับ 6 ชุดอักขระที่ Java ต้องการ foobar = new InputStreamReader(p.getInputStream(), Charset.ISO_8859_1);- ตอนนี้จะไม่ดีกว่าและหลีกเลี่ยงความผิดพลาดครั้งแล้วครั้งเล่า?
281377

3
ห้องสมุดฝรั่งมีสิ่งเหล่านี้มากมาย ทำให้ชีวิตง่ายขึ้น

3
Java 1.7+ มีค่าคงที่ชุดอักขระ: docs.oracle.com/javase/7/docs/api/java/nio/charset/… . ใช้พวกเขาอย่างนั้น: StandardCharsets.UTF_8.displayName ()
Michael

4

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


4

ส่วนหนึ่งของข้อยกเว้นเหล่านี้ที่ทำให้ฉันรำคาญที่สุดคือมันเจ็บรหัสที่ครอบคลุมของฉัน

เมื่อฉันได้รับการบังคับเกี่ยวกับการรายงานข่าวฉันจะสรุป / ลองว่า "ไม่เคยเกิดขึ้น" (... หรือเฉพาะในกรณีที่ฉันใช้ JVM กลายพันธุ์ที่บางคนลืมที่จะรวม "US-ASCII") ไว้ใน ชั้นเรียนและวิธีการที่แค็ปซูลที่ลอง / จับและแทนที่ข้อยกเว้นที่ตรวจสอบในหนึ่งในวิธีที่กล่าวถึงที่นี่ (มักจะโยนข้อยกเว้นที่ไม่ถูกตรวจสอบด้วยข้อความ snide)

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

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

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

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