Rethrowing ข้อยกเว้นใน Java โดยไม่สูญเสียการติดตามสแต็ก


417

ใน C # ฉันสามารถใช้throw;คำสั่งเพื่อสร้างข้อยกเว้นใหม่ในขณะที่รักษาการติดตามสแต็ก:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

มีบางอย่างเช่นนี้ใน Java ( ที่ไม่สูญเสียการติดตามสแต็กเดิม )?


4
ทำไมคุณถึงคิดว่ามันสูญเสีย stacktrace ดั้งเดิม? วิธีเดียวที่จะปล่อยมันออกมาเมื่อคุณโยน SomeOtherException ใหม่และลืมที่จะกำหนดสาเหตุที่แท้จริงของตัวสร้างหรือใน initCause ()
akarnokd

4
ฉันเชื่อว่านี่เป็นวิธีการทำงานของรหัสในสุทธิ แต่ฉันไม่ได้เป็นบวก มันอาจจะคุ้มค่าที่จะมองหาที่อื่นหรือทำการทดสอบเล็ก ๆ
ripper234

11
Throwableไม่ได้รับการแก้ไขโดยการขว้างพวกเขา fillInStackTrace()การอัปเดตกองติดตามคุณต้องโทร Throwableสิ่งอำนวยความสะดวกวิธีนี้ได้รับการเรียกในตัวสร้างของที่
Robert

50
ใน C # ใช่throw e;จะสูญเสีย stacktrace แต่ไม่ใช่ใน Java
ทิมกู๊ดแมน

คำตอบ:


560
catch (WhateverException e) {
    throw e;
}

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


4
สวัสดี InterruptedException e ให้ข้อความ Exception ที่ไม่สามารถจัดการได้เมื่อฉันเพิ่มบรรทัด E ไม่เช่นนั้นถ้าฉันแทนที่ด้วย exception ที่กว้างขึ้น e ควรทำสิ่งนี้อย่างถูกต้องอย่างไร?
James P.

1
@ James ฉันเพิ่งสังเกตว่าข้อความหายไปหากเพิ่ม "throw XxxException" ในการประกาศฟังก์ชั่น
shiouming

2
ในคอมไพเลอร์ Java 7 สำหรับการสร้างใหม่นั้นฉลาดกว่า ตอนนี้มันทำงานได้ดีกับข้อยกเว้น "การขว้าง" ที่เฉพาะเจาะจงในวิธีการที่มี
Waldemar Wosiński

193
@ James หากคุณcatch(Exception e) { throw e; }จะไม่ถูกจัดการ หากคุณcatch(InterruptedException ie) { throw ie; }จะได้รับการจัดการ ตามหลักการง่ายๆอย่าcatch(Exception e)- นี่ไม่ใช่โปเกมอนและเราไม่ต้องการจับพวกมันทั้งหมด!
corsiKa

3
@corsiKa มันไม่จำเป็นต้องเป็นความจริงที่คุณไม่ต้องการที่จะ "จับเลย" มันเป็นกรณีการใช้งานที่แตกต่างออกไป หากคุณมีลูประดับบนสุดหรือตัวจัดการเหตุการณ์ (ตัวอย่างเช่นในการรันเธรด) หากคุณไม่ได้ใช้งานอย่างน้อย RuntimeException และบันทึกมันคุณมักจะพลาดข้อยกเว้นทั้งหมดและแยกตัวออกจากลูปสำคัญ ๆ มักเป็นความล้มเหลวครั้งเดียว นอกจากนี้ยังเป็นเรื่องที่ดีสำหรับฟังก์ชั่นปลั๊กอินที่คุณไม่รู้ว่าโค้ดเพิ่มเติมอาจทำอะไรหรือโยน ... สำหรับการใช้งานจากบนลงล่างเช่นข้อยกเว้นที่ดึงดูดเหล่านี้มักจะไม่ใช่แค่ความคิดที่ดี แต่เป็นแนวปฏิบัติที่ดีที่สุด
Bill K

82

ฉันต้องการ:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}

6
เหมาะสมอย่างแน่นอนใน Java เพื่อจับข้อยกเว้นที่เฉพาะเจาะจงกว่าทั่วไปและการตรวจสอบตัวอย่างของ +1
amischiefr

8
-1 เนื่องจากคุณไม่ควรใช้ "ข้อยกเว้น" แบบธรรมดาเว้นแต่คุณจะรู้ว่าคุณกำลังทำอะไรอยู่
Stroboskop

19
@Stroboskop: จริง แต่เพื่อตอบที่ดีที่สุดคือใช้รหัสเดียวกัน (คล้าย) ในคำถาม!
user85421

14
บางครั้งการจับข้อยกเว้นทั้งหมดก็โอเค เช่นเมื่อคุณกำลังเขียนกรณีทดสอบ หรือเพื่อการเข้าสู่ระบบ หรือในหลักที่ไม่ได้หมายถึงการกระแทก
John Henckel

1
@JohnHenckel และคนอื่น ๆ : คะแนนถูกต้องแล้ว ฉันอัปเดตคำถามเพื่อให้ชัดเจนว่าการจับExceptionไม่ใช่ปกติในกรณีส่วนใหญ่ (แต่ไม่ใช่ทั้งหมด)
ต่อ Lundberg

74

คุณยังสามารถรวมข้อยกเว้นไว้ในอีกอันหนึ่งและเก็บสแต็กการติดตามดั้งเดิมไว้โดยส่งผ่านการยกเว้นเป็น Throwable เป็นพารามิเตอร์สาเหตุ:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}

8
ฉันจะแนะนำให้เพิ่มข้อความโดยใช้throw new YourOwnException("Error while trying to ....", e);
Julien

นี่คือสิ่งที่ฉันกำลังมองหาโดยเฉพาะอย่างยิ่งรุ่นจากความคิดเห็นแรกที่คุณสามารถส่งข้อความของคุณเอง
Csaba

สิ่งนี้แสดงข้อความแสดงข้อผิดพลาดอย่างถูกต้อง แต่การติดตามสแต็กแสดงบรรทัดข้อผิดพลาดตามบรรทัดที่มี 'โยนใหม่ ....... (e)' ไม่ใช่บรรทัดเดิมที่ทำให้เกิดข้อยกเว้น
Ashburn RK

22

ใน Java เกือบจะเหมือนกัน:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}

5
ไม่ตราบใดที่คุณไม่ยกตัวอย่างวัตถุยกเว้นใหม่สแต็คเทรซจะยังคงเหมือนเดิม
Mnementh

28
ฉันจะเพิ่มการจับที่เฉพาะเจาะจงสำหรับ FooException
DFA

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

1
@MarkusLausberg แต่ในที่สุดก็ไม่ได้รับการยกเว้น
Robert

ใช่ แต่นี่ไม่ใช่คำถาม
Markus Lausberg

14

ใน Java คุณเพียงแค่โยนข้อยกเว้นที่คุณจับได้ดังนั้นแทนที่จะเป็นเพียงthrow e throwJava เก็บการติดตามสแต็ก



5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

IOExceptionนี่คือตัวอย่างที่เป็นรูปธรรมที่วิธีการพ่น finalวิธีtเดียวที่สามารถถือเป็นข้อยกเว้นโยนลงมาจากบล็อกลอง อ่านเนื้อหาเพิ่มเติมสามารถพบได้ที่นี่และที่นี่


1
ไม่จำเป็นต้องเป็นครั้งสุดท้าย ดูdocs.oracle.com/javase/7/docs/technotes/guides/language/ …และstackoverflow.com/a/6889301/131160
jcsahnwaldt พูดว่า GoFundMonica

3

การติดตามสแต็กจะถูกดำเนินการถ้าคุณตัด excetion ที่ดักจับไว้ในข้อยกเว้นอื่น ๆ (เพื่อให้ข้อมูลเพิ่มเติม) หรือถ้าคุณเพิ่ง rethrow การดักจับที่ดักจับไว้

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }


2

ฉันเพิ่งมีสถานการณ์ที่คล้ายกันซึ่งรหัสของฉันอาจโยนข้อยกเว้นต่าง ๆ จำนวนมากที่ฉันเพียงต้องการ rethrow วิธีแก้ปัญหาที่อธิบายไว้ข้างต้นไม่ได้ผลสำหรับฉันเพราะ Eclipse บอกฉันว่าthrow e;นำไปสู่ข้อยกเว้นที่ไม่มีการแจ้งเตือนดังนั้นฉันเพิ่งทำสิ่งนี้:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

ทำงานให้ฉัน .... :)

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