ฉันสามารถตรวจจับข้อยกเว้น Java หลายข้อใน catch clause เดียวกันได้หรือไม่


702

ใน Java ฉันต้องการทำสิ่งนี้:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}

...แทน:

try {
    ...     
} catch (IllegalArgumentException e) {
    someCode();
} catch (SecurityException e) {
    someCode();
} catch (IllegalAccessException e) {
    someCode();
} catch (NoSuchFieldException e) {
    someCode();
}

มีวิธีการทำเช่นนี้?

คำตอบ:


1133

นี้ได้รับเป็นไปได้ตั้งแต่ Java 7 ไวยากรณ์สำหรับ multi-catch block คือ:

try { 
  ...
} catch (IOException | SQLException ex) { 
  ...
}

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

นอกจากนี้โปรดทราบว่าคุณไม่สามารถจับทั้ง ExceptionA และ ExceptionB ในบล็อกเดียวกันหาก ExceptionB นั้นได้รับการถ่ายทอดโดยตรงหรือโดยอ้อมจาก ExceptionA คอมไพเลอร์จะบ่นว่า:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA

81
TT - ทำไมต้องกำหนดตัวดำเนินการbitwise or( |) อีกครั้ง ทำไมไม่ใช้เครื่องหมายจุลภาคหรือตัวดำเนินการที่มีความหมายคล้ายกันมากขึ้นlogical or( ||)
ArtOfWarfare

11
@ArtOfWarfare บางทีพวกเขาคิดว่ามันจะไม่สำคัญอีกต่อไปหลังจากที่พวกเขามีไวยากรณ์สำหรับขอบเขตทั่วไปสำหรับ generics แล้ว
JimmyB

12
เครื่องหมาย XOR (I) ไม่เหมือนกับ OR (||), A | B หมายถึง A หรือ B แต่ไม่ใช่ทั้ง A || B หมายถึง A หรือ B หรือทั้งสองอย่างเพื่อเป็นข้อยกเว้นนั่นคือ exceptionA หรือ exceptionB แต่ไม่ใช่ทั้งสองอย่างในเวลาเดียวกัน นี่คือเหตุผลที่พวกเขาใช้ XOR ร้องเพลงแทน OR และคุณจะเห็นได้อย่างชัดเจนว่าเมื่อข้อยกเว้นถูกโยนหากคุณใส่ข้อยกเว้น 2 ข้อข้อหนึ่งข้อหนึ่งคือประเภทย่อยอีกอัน
user1512999

41
@ user1512999 ใน Java ค่าบิต XOR คือ ^ (caret) และ bitwise OR เป็น | (ท่อ) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Lewis Baumstark

6
เป็นมูลค่าการกล่าวขวัญว่าประเภทของข้อยกเว้นที่ติดอยู่ในบล็อกแบบ multi-catch นั้นได้รับการประเมินจากผู้ปกครองทั่วไปที่ได้รับมากที่สุด
yanpas

104

ไม่ใช่ก่อนหน้า Java 7 แต่ฉันจะทำสิ่งนี้:

Java 6 และก่อนหน้า

try {
  //.....
} catch (Exception exc) {
  if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
     exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) {

     someCode();

  } else if (exc instanceof RuntimeException) {
     throw (RuntimeException) exc;     

  } else {
    throw new RuntimeException(exc);
  }

}



Java 7

try {
  //.....
} catch ( IllegalArgumentException | SecurityException |
         IllegalAccessException |NoSuchFieldException exc) {
  someCode();
}

11
โปรดทราบว่าตัวอย่าง Java 6 ของคุณจะหยุดความสามารถของคอมไพเลอร์เพื่อบอกสิ่งที่จะถูกโยนออกมา
MichaelBlume

2
@MichaelBlume True ซึ่งไม่เลวร้ายนัก exc.getCause()คุณสามารถได้รับข้อยกเว้นเดิมที่มี ในฐานะที่เป็นข้อความด้านข้าง Robert C. Martin แนะนำให้ใช้ข้อยกเว้นที่ไม่มีการตรวจสอบ อ้างถึง บทที่ 7: จัดการข้อผิดพลาดในหนังสือของเขารหัสสะอาด
user454322

4
ในตัวอย่าง Java 6 ของคุณคุณไม่ควรสร้างข้อยกเว้นเดิมขึ้นมาใหม่แทนที่จะสร้างอินสแตนซ์ข้อยกเว้นใหม่นั่นคือthrow excแทนที่จะเป็นthrow new RuntimeException(exc)?
David DeMar

5
นี่เป็นวิธีปฏิบัติที่ไม่ดีงามจากมุมมองของการอ่าน
Rajesh J Advani

3
การดำเนินการของอินสแตนซ์เป็นบิตราคาแพงมันจะดีกว่าเพื่อหลีกเลี่ยงมาก
Paramesh Korrakuti

23

ภายใน Java 7 คุณสามารถกำหนด clauses ได้หลายรายการเช่น:

catch (IllegalArgumentException | SecurityException e)
{
    ...
}

16

หากมีลำดับชั้นของข้อยกเว้นคุณสามารถใช้คลาสฐานเพื่อตรวจสอบคลาสย่อยทั้งหมดของข้อยกเว้น ในกรณีที่เลวลงคุณสามารถตรวจจับข้อยกเว้น Java ทั้งหมดด้วย:

try {
   ...
} catch (Exception e) {
   someCode();
}

ในกรณีทั่วไปมากขึ้นถ้า RepositoryException เป็นคลาสพื้นฐานและ PathNotFoundException เป็นคลาสที่ได้รับแล้ว:

try {
   ...
} catch (RepositoryException re) {
   someCode();
} catch (Exception e) {
   someCode();
}

รหัสข้างต้นจะจับ RepositoryException และ PathNotFoundException สำหรับการจัดการข้อยกเว้นชนิดหนึ่งและข้อยกเว้นอื่น ๆ ทั้งหมดจะถูกรวมเข้าด้วยกัน ตั้งแต่ Java 7 ตามคำตอบของ @ OscarRyz ด้านบน:

try { 
  ...
} catch( IOException | SQLException ex ) { 
  ...
}

7
BTW catch clauses ได้รับการจัดการตามลำดับดังนั้นหากคุณใส่คลาส parent parent ก่อนคลาสเด็กจะไม่ถูกเรียกเช่น: ลอง {... } catch (Exception e) {someCode (); } catch (RepositoryException re) {// ไม่ถึง}
Michael Shopsin

4
ที่จริงแล้วแม่นยำเพราะมันไม่สามารถเข้าถึงได้รหัสดังกล่าวไม่ได้รวบรวม
polygenelubricants

15

ไม่ละหนึ่งลูกค้า

คุณสามารถจับซูเปอร์คลาสเช่น java.lang.Exception ตราบใดที่คุณดำเนินการแบบเดียวกันในทุกกรณี

try {
    // some code
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception
    e.printStackTrace();
}

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


20
ฉันขอให้คุณใช้ถ้อยคำใหม่ในส่วนที่เกี่ยวกับการจับ java.lang.Exception ได้หรือไม่? ฉันรู้ว่ามันเป็นตัวอย่าง แต่ฉันรู้สึกว่าบางคนอาจอ่านคำตอบนี้แล้วพูดว่า "โอเคฉันจะจับข้อยกเว้นแล้ว" เมื่อนั้นอาจไม่ใช่สิ่งที่พวกเขาต้องการ (หรือควร) ทำ
Rob Hruska

2
ผมรู้เกี่ยวกับที่ แต่ฉันไม่ต้องการที่จะทำมัน ... โอ้, ดี, คิดว่าฉันติดอยู่กับ 4 จับแล้วจนถึงรุ่นถัดไปของ Java ...
froadie

@duffymo: มีอะไรผิดปกติกับการเข้าสู่ระบบและ rethrowing? ยกเว้นว่ามันจะตัดรหัสมันเทียบเท่ากับที่จะไม่จับมันไม่ได้ เห็นได้จากมุมมองกลยุทธ์การจัดการข้อผิดพลาดทั่วไป สิ่งที่ไม่ดีคือการเข้าสู่ระบบและไม่คิดใหม่
Frank Osterfeld

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

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

10

ทำความสะอาด ( แต่น้อย verbose และบางทีอาจจะไม่เป็นที่ต้องการ) ทางเลือกที่จะตอบ user454322 บน Java 6 (เช่น Android) จะจับทั้งหมดExceptionและอีกครั้งโยนRuntimeExceptions นี้จะไม่ทำงานถ้าคุณวางแผนอยู่ในการจับประเภทอื่น ๆ ยกเว้นเพิ่มเติมขึ้นสแต็ค (ยกเว้นกรณีที่คุณยัง re-โยนพวกเขา) แต่มีประสิทธิภาพจะจับทั้งหมดตรวจสอบข้อยกเว้น

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

try {
    // CODE THAT THROWS EXCEPTION
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        // this exception was not expected, so re-throw it
        throw e;
    } else {
        // YOUR CODE FOR ALL CHECKED EXCEPTIONS
    } 
}

ที่ถูกกล่าวว่าสำหรับการใช้คำฟุ่มเฟื่อยมันเป็นสิ่งที่ดีที่สุดในการตั้งค่าบูลีนหรือตัวแปรอื่น ๆ และตามที่รันรหัสบางอย่างหลังจากบล็อกลองจับ


1
วิธีการนี้จะป้องกันคอมไพเลอร์ไม่ให้พิจารณาว่า "catch block" จะสามารถเข้าถึงได้หรือไม่
the_new_mr

3

ใน pre-7 จะทำอย่างไร:

  Boolean   caught = true;
  Exception e;
  try {
     ...
     caught = false;
  } catch (TransformerException te) {
     e = te;
  } catch (SocketException se) {
     e = se;
  } catch (IOException ie) {
     e = ie;
  }
  if (caught) {
     someCode(); // You can reference Exception e here.
  }

3
wuold เป็นทางออกที่ดี วิธีการแทรกการควบคุมขั้นสุดท้ายของcaughtในfinallyบล็อก?
Andrea_86

สิ่งนี้ต้องการบรรทัดมากกว่าคำถามเดิม
Leandro Glossman

1

ใช่. นี่คือวิธีการใช้ pipe (|) separator

try
{
    .......
}    
catch
{
    catch(IllegalArgumentException | SecurityException | IllegalAccessException | NoSuchFieldException e)
}

สไตล์โค้ดนี้คืออะไร? บล็อก catch เป็นบล็อกลอง?
แซม

1

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

try {
    // code
} catch(ex:Exception) {
    when(ex) {
        is SomeException,
        is AnotherException -> {
            // handle
        }
        else -> throw ex
    }
}

0

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

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