ลอง / จับกับโยนข้อยกเว้น


117

คำสั่งรหัสเหล่านี้เทียบเท่าหรือไม่ มีความแตกต่างกันหรือไม่?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

3
ไม่ใช่คำตอบจริงๆ แต่คุณอาจสนใจข้อยกเว้นของบทความของ Ned Batchelder ใน Rainforestซึ่งช่วยอธิบายกรณีทั่วไปที่ควรเลือกสไตล์หนึ่งหรือสไตล์อื่น
Daniel Pryden

1
แทนที่จะมี "showException (e)" ในการจับคุณถามว่าคุณมี "โยน e" ในการจับแทนหรือไม่ (หรือไม่ได้ลอง / จับเลย)
MacGyver

คำตอบ:


146

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

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

คุณจะสามารถที่จะบอกนี้เพราะคุณไม่สามารถเรียกวิธีแรกโดยไม่ต้องทั้งการจับExceptionตัวคุณเองหรือประกาศว่าวิธีการของคุณอาจจะโยนมันเกินไป


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

17
+1 เพราะ Jon Skeet ต้องการชื่อเสียงมากกว่านี้ โอ้และคำตอบก็ดีเช่นกัน
Jonathan Spiller

20

อันดับแรกthrows Exceptionดังนั้นผู้โทรต้องจัดการกับไฟล์Exception. ตัวที่สองจะจับและจัดการExceptionภายในดังนั้นผู้โทรจึงไม่ต้องจัดการข้อยกเว้นใด ๆ


สรุปได้ว่าฉันควรใช้อันที่สองเสมอ ฉันถูกไหม? วิธีแรกเป็นวิธีการที่ใช้ในจุดต่างๆของโปรแกรม นั่นเป็นเหตุผลที่ฉันตัดสินใจรวบรวมคำแนะนำสำหรับการใช้งานต่อไป แต่เมื่อทำเสร็จแล้วตอนนี้ฉันก็รู้แล้วว่า T ทำผิดพลาดครั้งใหญ่ ..
carlos

9
ไม่จำเป็นต้องใช้ทั้งสองรูปแบบ หากวิธีการของคุณสามารถจัดการกับข้อยกเว้นได้ให้ใช้รูปแบบที่สองหากไม่เป็นเช่นนั้นให้ใช้รูปแบบแรกเพื่อแจ้งเตือนผู้โทร
Andreas Dolk

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

16

ใช่. เวอร์ชันที่ประกาศthrows Exceptionจะต้องใช้รหัสการเรียกเพื่อจัดการข้อยกเว้นในขณะที่เวอร์ชันที่จัดการอย่างชัดเจนจะไม่

กล่าวคือ:

performCalculation();

เทียบกับการย้ายภาระในการจัดการข้อยกเว้นให้กับผู้โทร:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}

6

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

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


3

มีสถานการณ์เฉพาะอย่างหนึ่งที่เราไม่สามารถใช้การขว้างได้เราต้องใช้การลองจับ มีกฎ "วิธีการลบล้างไม่สามารถทิ้งข้อยกเว้นพิเศษใด ๆ นอกเหนือจากสิ่งที่คลาสพาเรนต์กำลังขว้าง" หากมีข้อยกเว้นพิเศษใด ๆ ที่ควรจัดการโดยใช้การลองจับ พิจารณาข้อมูลโค้ดนี้ มีคลาสฐานง่ายๆ

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

และเป็นคลาสที่ได้รับ:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

เมื่อเราต้องเรียก thread.sleep () เราถูกบังคับให้ใช้ try-catch ที่นี่เราไม่สามารถใช้:

 public void show() throws InterruptedException

เนื่องจากวิธีการแทนที่ไม่สามารถทำให้เกิดข้อยกเว้นเพิ่มเติมได้


ฉันเชื่อว่าทุกคนไม่ทราบเกี่ยวกับข้อแม้นี้ แหลมดี
ivanleoncz

1

ฉันคิดว่าโดย "เหมือน" คุณกำลังอ้างถึงพฤติกรรม

พฤติกรรมของฟังก์ชันสามารถกำหนดได้โดย:

1) ค่าที่ส่งคืน

2) โยนข้อยกเว้น

3) ผลข้างเคียง (เช่นการเปลี่ยนแปลงในฮีประบบไฟล์ ฯลฯ )

ในกรณีนี้วิธีแรกจะเผยแพร่ข้อยกเว้นใด ๆ ในขณะที่วิธีที่สองจะไม่มีข้อยกเว้นที่ตรวจสอบและกลืนข้อยกเว้นที่ไม่ได้ตรวจสอบส่วนใหญ่ด้วยดังนั้นพฤติกรรมจึงแตกต่างกัน

อย่างไรก็ตามหากคุณรับประกันว่า "ทำอะไรบางอย่าง" จะไม่เกิดข้อยกเว้นพฤติกรรมนั้นจะเหมือนกัน (แม้ว่าคอมไพเลอร์จะกำหนดให้ผู้เรียกจัดการกับข้อยกเว้นในเวอร์ชันแรก)

--edit--

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


1

หากคุณโยนข้อยกเว้นเมธอดลูก (ซึ่งแทนที่สิ่งนี้) ควรจัดการกับข้อยกเว้น

ตัวอย่าง:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}

0

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


0

ผู้เรียกใช้เมธอดนี้จะต้องตรวจจับข้อยกเว้นนี้หรือประกาศว่าจะเปลี่ยนใหม่ในลายเซ็นของเมธอด

private void calculateArea() throws Exception {
    // Do something
}

ในตัวอย่างบล็อกการลองจับด้านล่าง ผู้เรียกใช้วิธีนี้ไม่ต้องกังวลเกี่ยวกับการจัดการข้อยกเว้นเนื่องจากได้รับการดูแลแล้ว

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}

0
private void calculateArea() throws Exception {
    ....do something
}

สิ่งนี้ทำให้เกิดข้อยกเว้นดังนั้นผู้เรียกจึงต้องรับผิดชอบในการจัดการข้อยกเว้นนั้น แต่หากผู้โทรไม่จัดการข้อยกเว้นอาจเป็นเพราะมันจะมอบให้กับ jvm ซึ่งอาจส่งผลให้การยุติโปรแกรมผิดปกติ

ในขณะที่ในกรณีที่สอง:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

ที่นี่มีการจัดการข้อยกเว้นโดย callee ดังนั้นจึงไม่มีโอกาสที่จะยุติโปรแกรมผิดปกติ

ลองจับเป็นแนวทางที่แนะนำ

IMO,

  • โยนคำหลักที่ใช้กับข้อยกเว้นที่ตรวจสอบเป็นส่วนใหญ่เพื่อโน้มน้าวคอมไพเลอร์ แต่ไม่รับประกันการยุติโปรแกรมตามปกติ

  • โยนคีย์เวิร์ดมอบหมายความรับผิดชอบในการจัดการข้อยกเว้นให้
    กับผู้โทร (JVM หรือวิธีอื่น)

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

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