จับข้อยกเว้นและ rethrowing แต่ไม่ใช่ข้อยกเว้น


10

ฉันสะดุดรหัสมองสิ่งนี้:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() {
    throw new RuntimeException();
}

รหัสนี้ทำให้ฉันประหลาดใจเพราะมันดูเหมือนว่า - วิธีการที่run()มีความสามารถในการโยนExceptionเพราะมันจับExceptionแล้ว rethrows แต่วิธีการที่ไม่ได้ประกาศว่าจะโยนExceptionและเห็นได้ชัดว่าไม่จำเป็นต้องเป็น รหัสนี้รวบรวมได้ดี (ใน Java 11 อย่างน้อย)

ความคาดหวังของฉันคือฉันจะต้องประกาศthrows Exceptionในrun()-method

ข้อมูลเพิ่มเติม

ในทำนองเดียวกันหากdoSomethingมีการประกาศให้โยนIOExceptionดังนั้นIOExceptionจะต้องประกาศในวิธีการrun()เท่านั้นแม้ว่าExceptionจะถูกจับและโยนใหม่

void run() throws IOException {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() throws IOException {
    // ... whatever code you may want ...
}

คำถาม

Java มักชอบความชัดเจนเหตุผลของพฤติกรรมนี้คืออะไร มันเป็นอย่างนี้เสมอไหม? อะไรใน Java Language Specification อนุญาตให้run()วิธีการที่ไม่จำเป็นต้องประกาศthrows Exceptionในตัวอย่างโค้ดข้างต้น? (ถ้าฉันจะเพิ่มเข้าไป IntelliJ เตือนฉันว่าExceptionไม่เคยถูกโยนทิ้ง)


3
น่าสนใจ คุณกำลังใช้คอมไพเลอร์อะไร? ถ้าเป็นคอมไพเลอร์ IDE ให้ตรวจสอบด้วยjavac- ฉันเคยเจอกับกรณีที่คอมไพเลอร์ Eclipse นั้นอ่อนโยนกว่า
M. Prokhorov

2
ฉันสามารถทำซ้ำพฤติกรรมนี้ใน openjdk-8 การคอมไพล์ด้วย-source 1.6ค่าสถานะทำให้เกิดข้อผิดพลาดการคอมไพล์ตามที่คาดไว้ การคอมไพล์ด้วยความเข้ากันได้ของแหล่งที่มา 7 ไม่ทำให้เกิดข้อผิดพลาดในการรวบรวม
Vogel612

1
ดูเหมือนว่าคอมไพเลอร์ฉลาดขึ้นตั้งแต่ Java 7 และทำการตรวจสอบเพิ่มเติมเกี่ยวกับข้อยกเว้นจริงที่อาจถูกโยนทิ้งไป
michalk

2
คำถามนี้ไม่ซ้ำกันและสามารถหาคำตอบได้ในลิงก์ที่ฉันให้ไว้In detail, in Java SE 7 and later, when you declare one or more exception types in a catch clause, and rethrow the exception handled by this catch block, the compiler verifies that the type of the rethrown exception meets the following conditions : 1. 1. The try block is able to throw it. 2. There are no other preceding catch blocks that can handle it. 3. It is a subtype or supertype of one of the catch clause's exception parameters.
michalk

2
การทำซ้ำที่ทำเครื่องหมายไว้ในปัจจุบันมีความเกี่ยวข้องอย่างแน่นอน แต่ไม่ได้ให้คำตอบ IMO โดยละเอียดเพียงพอ มีลิงก์หนึ่งลิงก์ไปยัง JLS ในความคิดเห็นไปยังคำตอบที่นั่นนอกจากนั้นไม่มีข้อมูล
Simon Forsberg

คำตอบ:


0

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


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

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

คุณจะเห็นพฤติกรรมที่แตกต่างเพราะตอนนี้javacสามารถบอกได้ว่ามีสิ่งใหม่Exceptionที่คุณกำลังขว้างปาไม่เกี่ยวข้องกับพฤติกรรมที่คุณจับได้

แต่สิ่งที่อยู่ไกลจากอุดมคติคุณสามารถ "หลอก" คอมไพเลอร์ได้อีกครั้งผ่าน:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        ex2 = ex;
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

IMO เพราะex2 = ex;มันไม่ควรจะล้มเหลวอีกครั้ง แต่มันก็เป็นเช่นนั้น

ในกรณีที่มันถูกคอมไพล์ด้วย javac 13+33


ฉันอ่านในลิงค์บางอันที่มีคนระบุว่าหากคุณมอบหมายข้อยกเว้นที่ตรวจพบใหม่ใน catch-block แล้วคอมไพเลอร์จะไม่สามารถฉลาดได้ ฉันคิดว่าสิ่งที่คล้ายกันใช้ในกรณีนี้ คอมไพเลอร์รู้ว่าex2ข้อยกเว้นจะถูกโยน แต่เดิมสร้างขึ้นเป็นExceptionแต่ถูกกำหนดใหม่แล้วexดังนั้นคอมไพเลอร์จึงไม่สามารถฉลาดได้
Simon Forsberg

@SimonForsberg ใครบางคนที่มีความปรารถนาที่JLSจะมาและให้คำพูดที่จำเป็นเพื่อพิสูจน์สิ่งนี้ น่าเสียดายที่ฉันไม่มี
ยูจีน

สำหรับเร็กคอร์ดเมื่อฉันเปลี่ยน catch catch เพื่อให้มีการกำหนดใหม่ของ catch exception ให้กับตัวเอง ( ex = ex;) heuristic จะไม่ถูกนำไปใช้อีกต่อไป พฤติกรรมนี้ดูเหมือนว่าจะใช้กับทุกระดับของแหล่งที่มาจาก 7 ถึง 11 และอาจ 13
Vogel612

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