Tôi có thể bắt nhiều ngoại lệ Java trong cùng một mệnh đề bắt không?


699

Trong Java, tôi muốn làm một cái gì đó như thế này:

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

...thay vì:

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

Có cách nào để làm điều này?

Câu trả lời:


1131

Điều này đã có thể kể từ Java 7 . Cú pháp cho một khối đa bắt là:

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

Tuy nhiên, hãy nhớ rằng nếu tất cả các ngoại lệ thuộc về cùng một hệ thống phân cấp lớp, bạn có thể chỉ cần bắt loại ngoại lệ cơ sở đó.

Cũng lưu ý rằng bạn không thể bắt cả ExceptionA và ExceptionB trong cùng một khối nếu ExceptionB được kế thừa, trực tiếp hoặc gián tiếp, từ ExceptionA. Trình biên dịch sẽ khiếu nại:

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

81
TT - tại sao xác định lại toán tử bitwise or( |)? Tại sao không sử dụng dấu phẩy hoặc toán tử có ý nghĩa tương tự hơn, logical or( ||)?
ArtOfWarfare

11
@ArtOfWarfare Có lẽ họ nghĩ rằng điều đó sẽ không còn quan trọng nữa sau khi họ đã đưa ra cú pháp cho nhiều giới hạn cho thuốc generic.
JimmyB

12
Dấu XOR (I) không giống với OR (||), A | B có nghĩa là A hoặc B nhưng không phải cả A | | B có nghĩa là A hoặc B hoặc cả hai vì vậy, ngoại lệ, đó là ngoại lệ hoặc ngoại lệB nhưng không phải cả hai cùng một lúc. đây là lý do tại sao họ sử dụng XOR sing thay vì OR và bạn có thể thấy rõ điều đó khi ngoại lệ được ném nếu bạn đặt 2 ngoại lệ, một trong số đó là loại phụ của người khác
user1512999

41
@ user1512999 trong Java, XOR bitwise là ^ (dấu mũ) và bitwise OR là | (ống) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Lewis Baumstark

6
Điều đáng nói là loại ngoại lệ bị bắt trong khối đa bắt được đánh giá theo cha mẹ phổ biến nhất có nguồn gốc
yanpas

104

Không chính xác trước Java 7 nhưng, tôi sẽ làm một cái gì đó như thế này:

Java 6 trở về trước

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
Lưu ý rằng ví dụ Java 6 của bạn phá vỡ khả năng của trình biên dịch để cho biết thứ gì sẽ được ném từ đâu.
MichaelBlume

2
@MichaelBlume Đúng, điều đó không [xấu]. Bạn luôn có thể có được ngoại lệ ban đầu với exc.getCause(). Là một lưu ý phụ, Robert C. Martin (trong số những người khác) khuyên bạn nên sử dụng các ngoại lệ không được kiểm tra (trình biên dịch không có ý tưởng về loại ngoại lệ nào sẽ được ném từ đó); tham khảo Chương 7: Xử lý lỗi trên cuốn sách của mình Mã sạch .
dùng454322

4
Trong ví dụ Java 6 của bạn, bạn không nên lấy lại ngoại lệ ban đầu thay vì tạo một cá thể ngoại lệ mới, tức là throw excthay vì throw new RuntimeException(exc)?
David DeMar

5
Đây là thực tế khá xấu, từ quan điểm của khả năng đọc.
Rajesh J Advani

3
Hoạt động của Instanceof hơi tốn kém, tốt hơn hết là tránh càng nhiều càng tốt.
Paramesh Korrakuti

23

Trong Java 7, bạn có thể định nghĩa nhiều mệnh đề bắt như:

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

16

Nếu có một hệ thống ngoại lệ, bạn có thể sử dụng lớp cơ sở để bắt tất cả các lớp ngoại lệ. Trong trường hợp suy biến, bạn có thể bắt tất cả các ngoại lệ Java với:

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

Trong một trường hợp phổ biến hơn nếu Rep repositoryException là lớp cơ sở và PathNotFoundException là một lớp dẫn xuất thì:

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

Đoạn mã trên sẽ bắt Rep RepExException và PathNotFoundException cho một loại xử lý ngoại lệ và tất cả các ngoại lệ khác được gộp lại với nhau. Kể từ Java 7, theo câu trả lời của @ OscarRyz ở trên:

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

7
Các mệnh đề bắt BTW được xử lý theo thứ tự vì vậy nếu bạn đặt một lớp ngoại lệ cha mẹ trước một lớp con thì nó sẽ không bao giờ được gọi là: thử {...} Catch (Exception e) {someCode (); } Catch (
Rep StorageException

4
Thực tế chính xác bởi vì nó không bao giờ có thể đạt được, mã như vậy thậm chí không biên dịch.
đa gen

15

Không, một cho mỗi khách hàng.

Bạn có thể bắt một siêu lớp, như java.lang.Exception, miễn là bạn thực hiện cùng một hành động trong mọi trường hợp.

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

Nhưng đó có thể không phải là cách thực hành tốt nhất. Bạn chỉ nên bắt một ngoại lệ khi bạn có một chiến lược để thực sự xử lý nó - và ghi nhật ký và suy nghĩ lại không phải là "xử lý nó". Nếu bạn không có hành động khắc phục, tốt hơn là thêm nó vào chữ ký phương thức và để nó nổi lên với ai đó có thể xử lý tình huống.


20
Tôi có thể kiến ​​nghị bạn viết lại phần về việc bắt java.lang.Exception không? Tôi nhận ra rằng đó là một ví dụ, nhưng tôi cảm thấy như một số người có thể đọc câu trả lời này và nói, "ồ, được rồi, tôi sẽ bắt Exception rồi", khi đó có lẽ không phải là điều họ muốn (hoặc nên) làm.
Rob Hruska

2
Tôi biết về điều đó, nhưng tôi không muốn làm điều đó ... Ồ, hãy đoán rằng tôi đã bị mắc kẹt với 4 lần bắt, cho đến phiên bản tiếp theo của Java ...
froadie

@duffymo: Có gì sai khi đăng nhập và suy nghĩ lại? Ngoại trừ việc nó mã hóa mã, tương đương với việc không bắt được mã, không phải là nó. Nhìn từ quan điểm chiến lược xử lý lỗi chung. Điều gì xấu là đăng nhập và không suy nghĩ lại .
Frank Osterfeld

5
Tôi không xem xét việc đăng nhập và xử lý lại bất cứ điều gì. Tôi muốn để nó nổi bong bóng lên với một người có thể làm điều gì đó có ý nghĩa. Lớp cuối cùng mà ngoại lệ không bao giờ thoát ra (ví dụ: bộ điều khiển trong ứng dụng web) sẽ là lớp ghi nhật ký lỗi trong trường hợp đó.
duffymo

Tôi có phải là người duy nhất thấy vô lý khi một bản ghi không được tạo tự động cho tôi không? Dường như tất cả chúng ta đều phải viết cùng một thông điệp ghi nhật ký ngu ngốc mỗi khi một đoạn mã nào đó có thể đưa ra một ngoại lệ.
ArtOfWarfare

10

Một cách thay thế sạch hơn (nhưng ít dài dòng hơn và có lẽ không được ưu tiên hơn) cho câu trả lời của người dùng454322 trên Java 6 (nghĩa là Android) sẽ là bắt tất cả Exceptions và ném lại RuntimeExceptions. Điều này sẽ không hoạt động nếu bạn dự định bắt các loại ngoại lệ khác trong ngăn xếp (trừ khi bạn cũng ném lại chúng), nhưng sẽ bắt được tất cả các ngoại lệ được kiểm tra một cách hiệu quả .

Ví dụ:

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
    } 
}

Điều đó đang được nói, đối với tính dài dòng, tốt nhất nên đặt một boolean hoặc một số biến khác và dựa vào đó thực thi một số mã sau khối thử bắt.


1
Cách tiếp cận này ngăn trình biên dịch xác định liệu "khối bắt" có thể truy cập được hay không.
the_new_mr

3

Trong trước 7 như thế nào về:

  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 là một giải pháp tốt đẹp. Làm thế nào về việc chèn điều khiển cuối cùng caughttrong một finallykhối?
Andrea_86

Điều này đòi hỏi nhiều dòng hơn câu hỏi ban đầu.
Leandro Glossman

1

Đúng. Đây là cách sử dụng dấu phân cách đường ống (|),

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

Kiểu mã này là gì? Các khối bắt thành một khối thử?
Sam

1

Đối với kotlin, hiện tại không thể nhưng họ đã cân nhắc thêm nó: Nguồn
Nhưng hiện tại, chỉ là một mẹo nhỏ:

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

0

Bắt ngoại lệ xảy ra là một lớp cha trong hệ thống phân cấp ngoại lệ. Điều này là tất nhiên, thực hành xấu . Trong trường hợp của bạn, ngoại lệ cha mẹ phổ biến là lớp Exception và bắt bất kỳ ngoại lệ nào là ngoại lệ, thực sự là thực tiễn xấu - các ngoại lệ như NullPulumException thường là lỗi lập trình và thường được giải quyết bằng cách kiểm tra các giá trị null.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.