เหตุใด“ ข้อยกเว้นการโยน” จึงจำเป็นเมื่อเรียกใช้ฟังก์ชัน


102
class throwseg1
{
    void show() throws Exception
    {
        throw new Exception("my.own.Exception");
    }

    void show2() throws Exception  // Why throws is necessary here ?
    {
        show();
    }

    void show3() throws Exception  // Why throws is necessary here ?
    {
        show2();
    }

    public static void main(String s[]) throws Exception  // Why throws is necessary here ?
    {
        throwseg1 o1 = new throwseg1();
        o1.show3();
    }
}

ทำไมรายงานคอมไพเลอร์ว่าวิธีการshow2(), show3()และmain()มี

ข้อยกเว้นที่ไม่รายงานข้อยกเว้นที่ต้องถูกจับหรือประกาศว่าถูกโยนทิ้ง

เมื่อฉันลบออกthrows Exceptionจากวิธีการเหล่านี้?


2
@PaulTomblin main สามารถประกาศให้ยกเลิก Exception ได้อย่างแน่นอน หากเป็นเช่นนั้น JVM จะปิดตัวลง นี่ใกล้เคียงกับการละเว้นเท่าที่คอมไพเลอร์จะอนุญาต
Taymon

เมื่อเมธอดที่เรียกว่า ( Methdod1 ) พ่นExceptionเราต้องกำหนดวิธีการเรียก ( Method2 ) ด้วยthrows Exception; หากเราไม่ได้มอบข้อยกเว้นนั้นในวิธีการโทร จุดประสงค์ของสิ่งนี้คือเพื่อให้ทราบถึงวิธีการเรียก ( Method3 ) ของMethod2ว่าข้อยกเว้นอาจถูกโยนทิ้งโดยMethod2และคุณควรจัดการที่นี่มิฉะนั้นอาจขัดขวางโปรแกรมของคุณ
Rito

ในทำนองเดียวกันถ้าMethod3ไม่จัดการข้อยกเว้นในร่างกายก็จะต้องกำหนดthrows Exceptionในนิยามวิธีการเพื่อให้ทราบถึงวิธีการโทร ส่วนขยายของความคิดเห็นก่อนหน้า
Rito

คำตอบ:


148

อย่างที่คุณทราบใน Java ข้อยกเว้นสามารถแบ่งออกได้เป็นสองประเภท: ข้อยกเว้นที่ต้องการthrowsคำสั่งหรือต้องได้รับการจัดการหากคุณไม่ระบุอย่างใดอย่างหนึ่งและอีกข้อหนึ่งที่ไม่มี ตอนนี้ดูรูปต่อไปนี้:

ป้อนคำอธิบายภาพที่นี่

ใน Java คุณสามารถโยนอะไรก็ได้ที่ขยายThrowableชั้นเรียน อย่างไรก็ตามคุณไม่จำเป็นต้องระบุthrowsอนุประโยคสำหรับทุกชั้นเรียน โดยเฉพาะอย่างยิ่งคลาสที่เป็นErrorหรือRuntimeExceptionหรือคลาสย่อยของสองคลาสนี้ ในกรณีของคุณExceptionไม่ใช่คลาสย่อยของErrorหรือRuntimeException. ดังนั้นจึงเป็นข้อยกเว้นที่ตรวจสอบแล้วและต้องระบุไว้ในส่วนthrowsคำสั่งหากคุณไม่จัดการข้อยกเว้นนั้น นั่นคือเหตุผลที่คุณต้องการthrowsประโยค


จากJava Tutorial :

ข้อยกเว้นคือเหตุการณ์ที่เกิดขึ้นระหว่างการทำงานของโปรแกรมที่ขัดขวางขั้นตอนปกติของคำสั่งของโปรแกรม

ตอนนี้ดังที่คุณทราบข้อยกเว้นแบ่งออกเป็นสองประเภท: เลือกและไม่เลือก ทำไมต้องจัดหมวดหมู่เหล่านี้?

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

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

  • ข้อยกเว้นรันไทม์:มักเกิดขึ้นเนื่องจากความผิดพลาดของโปรแกรมเมอร์ ตัวอย่างเช่นหากการArithmeticExceptionหารด้วยศูนย์เกิดขึ้นหรือArrayIndexOutOfBoundsExceptionเกิดขึ้นนั่นเป็นเพราะเราไม่ระมัดระวังในการเขียนโค้ดมากพอ มักเกิดขึ้นเนื่องจากข้อผิดพลาดบางประการในตรรกะโปรแกรมของเรา ดังนั้นพวกเขาจะต้องถูกล้างก่อนที่โปรแกรมของเราจะเข้าสู่โหมดการผลิต พวกเขาจะไม่ถูกตรวจสอบในแง่ที่ว่าโปรแกรมของเราจะต้องล้มเหลวเมื่อเกิดขึ้นเพื่อให้เราโปรแกรมเมอร์สามารถแก้ไขได้ในขณะที่พัฒนาและทดสอบตัวเอง

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

สำหรับข้อมูลโดยละเอียดโปรดดู:


สิ่งที่ฉันได้จากคำตอบของคุณคือคลาสข้อผิดพลาดและคลาสย่อยและคลาส RuntimeException และคลาสย่อยของมันอยู่ภายใต้ข้อยกเว้นที่ไม่ได้ตรวจสอบ (เช่น System.out.println (5/0) ไม่จำเป็นต้องโยนเนื่องจากเป็น ข้อยกเว้นรันไทม์ แต่เรายังสามารถใช้ try catch ได้) และมีการตรวจสอบคลาส Exception ดังนั้นเราจึงต้องประกาศ throws clause ในเมธอดนั้นและทุกเมธอดที่เรียกมัน
nr5

อีกหนึ่งคำถาม: หากข้อยกเว้นถูกจัดหมวดหมู่ให้ไม่ถูกตรวจสอบและตรวจสอบโดยเฉพาะอย่างยิ่งข้อผิดพลาดที่ไม่ได้ตรวจสอบ (ข้อผิดพลาดรันไทม์) เพื่อหลีกเลี่ยงข้อผิดพลาดจำนวนมากขึ้นในระหว่างเวลาคอมไพล์?
5

@Jomoos - บอกว่าโค้ดในเมธอดพ่น IOException ถ้าอย่างนั้นจะใส่ "throws Exception" ในการประกาศเมธอดได้หรือไม่?
MasterJoe

โอ้. ฉันเข้าใจแล้ว. มีข้อยกเว้นสำหรับกฎของลำดับชั้นข้อยกเว้น ทำให้. สมบูรณ์แบบ. ความรู้สึก. ขอบคุณ Java
JJS

25

Java ต้องการให้คุณจัดการหรือประกาศข้อยกเว้นทั้งหมด หากคุณไม่ได้จัดการกับ Exception โดยใช้ try / catch block จะต้องมีการประกาศในลายเซ็นของเมธอด

ตัวอย่างเช่น:

class throwseg1 {
    void show() throws Exception {
        throw new Exception();
    }
}

ควรเขียนเป็น:

class throwseg1 {
    void show() {
        try {
            throw new Exception();
        } catch(Exception e) {
            // code to handle the exception
        }
    }
}

ด้วยวิธีนี้คุณสามารถกำจัดการประกาศ "throws Exception" ในการประกาศเมธอด


7
ข้อยกเว้นทั้งหมดที่ไม่ใช่คลาสย่อยRuntimeExceptionนั่นคือ
yshavit

ว่ามีคลาสอื่นเช่น Exception ที่ตรวจสอบไหม
nr5

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

ถ้าฉันจะบอกว่าข้อยกเว้นที่ตรวจสอบจำเป็นต้องได้รับการจัดการ @ รวบรวมเวลาและถูกจับที่รันไทม์ ฉันถูกไหม ? ถ้าใช่แล้วการใช้ประโยคเดียวกันสำหรับ Unchecked except จะเป็นอย่างไร
nr5

@ jebar8 - คุณกำลังสับสน Java กับ. NET - ใน Java, throwables ต้องสืบทอดThrowable(การสืบทอดExceptionยังใช้งานได้เพราะขยายThrowableได้ แต่ไม่จำเป็น)
BrainSlugs83

5

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

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

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

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

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

สิ่งที่ดีเกี่ยวกับการแก้ปัญหาประเภทนี้คือเมื่อคอมไพเลอร์รายงานError: Unhandled exception type java.io.IOExceptionว่าจะให้ไฟล์และหมายเลขบรรทัดของเมธอดที่ประกาศว่าจะทิ้งข้อยกเว้น จากนั้นคุณสามารถเลือกเพียงแค่ส่งบัคและประกาศว่าวิธีการของคุณ "พ่น IOException" ซึ่งสามารถทำได้จนถึงเมธอดหลักซึ่งจะทำให้โปรแกรมหยุดทำงานและรายงานข้อยกเว้นให้ผู้ใช้ทราบ อย่างไรก็ตามควรจับข้อยกเว้นและจัดการด้วยวิธีที่ดีเช่นอธิบายให้ผู้ใช้เข้าใจว่าเกิดอะไรขึ้นและจะแก้ไขอย่างไร เมื่อเมธอดจับและจัดการกับข้อยกเว้นก็ไม่จำเป็นต้องประกาศข้อยกเว้นอีกต่อไป คนเจ้าชู้หยุดอยู่ที่นั่นเพื่อที่จะพูด


4

Exceptionเป็นคลาสข้อยกเว้นที่ถูกตรวจสอบ ดังนั้นโค้ดใด ๆ ที่เรียกเมธอดที่ประกาศว่าthrows Exceptionต้องจัดการหรือประกาศ


ทุกวิธีในห่วงโซ่จะถูกประกาศให้ทิ้ง Exception รวมถึง main ด้วย แล้วปัญหาอยู่ที่ไหน?
Paul Tomblin

@PaulTomblin ฉันถามว่าเหตุใดจึงจำเป็นต้องเขียนข้อยกเว้นในฟังก์ชันการโทรเรียกฟังก์ชันที่แสดงข้อยกเว้น
nr5

โอเคฉันไม่เข้าใจว่าทำไมคุณถึงถามเกี่ยวกับข้อผิดพลาดของคอมไพเลอร์ที่คุณไม่ได้รับจากโค้ดที่คุณโพสต์ นั่นเป็นวิธีการถามที่แปลก
Paul Tomblin

0
package javaexception;


public class JavaException {
   void show() throws Exception
    {
        throw new Exception("my.own.Exception");
    }

void show2() throws Exception  // Why throws is necessary here ?
{
    show();
}

void show3() throws Exception  // Why throws is necessary here ?
{
    show2();
}
public static void main(String[] args) {

   JavaException a = new JavaException();

   try{
   a.show3();
   }catch(Exception e){
       System.out.println(e.getMessage());
   }
}

การเปลี่ยนแปลงเพียงเล็กน้อยในโปรแกรมของคุณ สิ่งที่หลายคนเข้าใจผิดเกี่ยวกับปัญหาหลักคือเมื่อใดก็ตามที่คุณโยนข้อยกเว้นที่คุณต้องจัดการไม่จำเป็นต้องอยู่ในที่เดียวกัน (เช่นวิธี show1,2,3 ในโปรแกรมของคุณ) แต่คุณต้องใช้วิธีการโทรก่อน ภายใน 'หลัก' ในคำเดียวคือ "โยน" ต้องมี "จับ / ลอง" แม้ว่าจะไม่ใช่วิธีการเดียวกันก็ตามที่มีข้อยกเว้นเกิดขึ้น


0
void show() throws Exception
{
    throw new Exception("my.own.Exception");
}

เนื่องจากมีการตรวจสอบข้อยกเว้นใน show () วิธีการซึ่งไม่ได้รับการจัดการในวิธีการนั้นดังนั้นเราจึงใช้คำหลักพ่นเพื่อเผยแพร่ข้อยกเว้น

void show2() throws Exception //Why throws is necessary here ?
{
show();
}

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


0

หากคุณเผยแพร่ข้อยกเว้นโดยการประกาศคำสั่งการพ่นในลายเซ็นของวิธีการปัจจุบันจะต้องใช้โครงสร้าง try / catch ที่บางแห่งในบรรทัดหรือเรียกใช้เพื่อจัดการกับข้อยกเว้น


ควรเพิ่มความคิดเห็นนี้ในส่วนความคิดเห็นเนื่องจากไม่ได้ให้คำตอบที่ตรวจสอบได้หรือเป็นตัวอย่าง - stackoverflow.com/help/how-to-answer
Paul Dawson

-1

โดยทั่วไปหากคุณไม่ได้จัดการข้อยกเว้นในสถานที่เดียวกับที่คุณกำลังขว้างปาคุณสามารถใช้ "ข้อยกเว้นการโยน" ที่นิยามของฟังก์ชัน

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