2012-01-20 34 views
12

Vâng, tôi nhận được thông qua các câu hỏi liên quan, tôi đã đọc mã nguồn của JDK 1.7, nhưng tôi không tìm thấy câu trả lời.JDK 1.7 Phương thức `addSuppressed()` có thể ném được

Trong câu hỏi này, tôi muốn bỏ qua hoàn toàn fillInStackTrace.

Phương thức JDK 1.4 initCause() đã được thêm vào. Ví dụ, khi bạn sử dụng phản chiếu cốt lõi để gọi phương thức bạn nhận được InvocationTargetException với nguyên nhân có ngoại lệ đích trong nó.

Khi tôi thấy tính năng này tôi bắt đầu sử dụng nó cũng trong một kịch bản như thế này

try { 
     //contains some code that can throw new IOException(); 
    } 
    catch(IOException e){ 
     throw new RuntimeException(e); 
    } 

Vì vậy, tôi bắt một ngoại lệ, tôi chưa sẵn sàng để đối phó với nó ở đây và tôi rethrow ngoại lệ mới nơi tôi có ngoại lệ ban đầu là nguyên nhân. Trong một số scenarious không RuntimeException, nhưng ngoại lệ tùy chỉnh của tôi được sử dụng, vì vậy đôi khi tôi cũng gọi đến e.getCause() để xử lý đúng ngoại lệ này trong khối bên ngoài.

Đây là tình huống trước JDK 1.7. Tại sao và khi nào tôi nên sử dụng addSuppressed()? Tôi có nên thay đổi mã ở trên để

try { 
     //contains some code that can throw new IOException(); 
    } 
    catch(IOException e){ 
     RuntimeException re= new RuntimeException(e.getMessage()); 
     re.addSuppressed(e); 
     throw re; 
    } 

Và như một câu hỏi tại sao tiền thưởng không addSuppressed() trở Throwable như initCause() không cho phép throw (RuntimeException)new RuntimeException().initCause(e);? Ví dụ tại sao tôi không thể làm ?:

try { 
     //contains some code that can throw new IOException(); 
    } 
    catch(IOException e){ 
     throw (RuntimeException)new RuntimeException(e.getMessage()).addSuppressed(e); 
    } 

tôi trích ra câu trả lời cho một bài riêng biệt.

+0

bạn không hiểu gì từ javadoc của phương pháp được đề cập? tôi chưa bao giờ thấy phương thức 'addSuppressed()' trước đây, nhưng việc đọc nhanh javadoc đã làm cho nó rõ ràng mục đích của nó là gì. (gợi ý, trong trường hợp sử dụng ví dụ của bạn nó sẽ _not_ có ý nghĩa). – jtahlborn

+1

Vâng, javadoc là không đủ. Tại sao downvote câu hỏi? – alexsmail

+0

tại sao không đủ, bạn không hiểu gì? – jtahlborn

Trả lời

11

Nói chung, Throwable addSuppressed() phương pháp nên được sử dụng khi một cách nào đó chúng ta có song song thực hiện mà có thể tạo ra ngoại lệ, đó là nơi đàn áp. Tôi đã tìm thấy 2 ví dụ;

  • Khối try-with-resource (khối try-finally) khi mã gọi sẽ thấy ngoại lệ ban đầu (trong khối try hoặc catch) và ngoại lệ xảy ra trong khối cuối cùng.

  • công việc hàng loạt (số lượng lớn các hoạt động) khi chúng ta nên tiến tới mục tiếp theo bất kể các hoạt động trên mục hiện thành công hay không

Trước khi đi vào chi tiết, như @sarelbotha phát biểu: trong trường hợp của tôi, tôi chỉ phải giữ nguyên ngoại lệ ban đầu là nguyên nhân của ngoại lệ mới của tôi.

Hành vi mặc định trong khối thử cuối cùng, trong đó chúng tôi có 2 ngoại lệ, ngoại lệ ban đầu là bị chặn và chúng tôi chỉ thấy ngoại lệ từ cuối cùng chặn. Nếu cuối cùng chúng ta sử dụng khối để đóng tài nguyên hơn là chúng ta thực sự muốn xem ngoại lệ ban đầu, nhưng chúng ta cũng muốn xem các ngoại lệ từ khối cuối cùng, đóng tài nguyên của chúng ta và thất bại.

Kể từ phiên bản 7, nền tảng hỗ trợ khái niệm về ngoại lệ bị loại bỏ (kết hợp với câu lệnh try-with-resources). Bất kỳ ngoại lệ nào bị chặn để phân phối ngoại lệ được in ra bên dưới dấu vết ngăn xếp.

http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#printStackTrace%28%29

Đầu tiên ta nên đọc về thử với các tài nguyên tính năng mới. Bạn có thể đọc tại đây http://www.baptiste-wicht.com/2010/08/java-7-try-with-resources-statement/ ví dụ hoặc tại đây What is the Java 7 try-with-resources bytecode equivalent using try-catch-finally?. Trong ngắn hạn, bạn có thể có 2 Throwable song song trong một số ý nghĩa, thường là từ bạn thử khối và từ khối cuối cùng của bạn. Một ngữ nghĩa try-catch cũ sẽ trả về ngoại lệ từ khối whule cuối cùng bị chặn ngoại lệ từ khối try (hoặc rethrowing exception từ khối catch). Một tính năng thử-với-tài nguyên mới cho phép bạn có được cả hai ngoại lệ. Thậm chí nhiều hơn, bạn sẽ nhận được ngoại lệ ban đầu nơi ngoại lệ từ khối cuối cùng sẽ được đàn áp

Lưu ý rằng khi một ngoại lệ gây ra ngoại lệ khác, ngoại trừ đầu tiên thường bị bắt và sau đó ngoại trừ thứ hai được ném trong phản ứng. Nói cách khác, có một mối quan hệ nhân quả giữa hai trường hợp ngoại lệ. Ngược lại, có những tình huống mà hai ngoại lệ độc lập có thể được ném vào các khối mã anh chị em, đặc biệt trong khối try của câu lệnh try-with-resources và khối cuối cùng do trình biên dịch tạo ra đóng tài nguyên. Trong những tình huống này, chỉ có một trong các ngoại lệ được ném có thể được nhân giống. Trong câu lệnh try-with-resources, khi có hai ngoại lệ như vậy, ngoại lệ bắt nguồn từ khối try được truyền và ngoại lệ từ khối cuối cùng được thêm vào danh sách các ngoại lệ bị loại trừ bởi ngoại lệ từ khối try. Là một ngoại lệ giải phóng stack, nó có thể tích lũy nhiều ngoại lệ bị chặn.

Ví dụ:

public class TestClass { 
static class ResourceA implements AutoCloseable{ 
     public void read() throws Exception{ 
     throw new Exception("ResourceA read exception"); 
     } 
     @Override 
     public void close() throws Exception { 
     throw new Exception("ResourceA close exception"); 
     } 
    }; 

static class ResourceB implements AutoCloseable{ 
     public void read() throws Exception{ 
     throw new Exception("ResourceB read exception"); 
     } 
     @Override 
     public void close() throws Exception { 
     throw new Exception("ResourceB close exception"); 
     } 
    }; 

    //a test method 
    public static void test() throws Exception{ 
     try (ResourceA a = new ResourceA(); 
      //ResourceB b = new ResourceB() 
      ) { 
     a.read(); 
     //b.read(); 
     } catch (Exception e) { 
     throw e; 
     } 
    } 

    public static void main(String[] args) throws Exception { 
     test(); 
    } 

}

Output sẽ là như sau:

Exception in thread "main" java.lang.Exception: ResourceA read exception 
at TestClass$ResourceA.read(TestClass.java:6) 
at TestClass.test(TestClass.java:29) 
at TestClass.main(TestClass.java:39) 
Suppressed: java.lang.Exception: ResourceA close exception 
    at TestClass$ResourceA.close(TestClass.java:10) 
    at TestClass.test(TestClass.java:31) 
    ... 1 more 

công việc hàng loạt (thao tác hàng loạt). Vâng, tôi đã tìm thấy một số cách sử dụng phương pháp này ngoài các tài nguyên thử. Dưới đây, là mã nguồn từ java.net.URLClassLoader.close

các
public void close() throws IOException { 
    SecurityManager security = System.getSecurityManager(); 
    if (security != null) { 
     security.checkPermission(new RuntimePermission("closeClassLoader")); 
    } 
    List<IOException> errors = ucp.closeLoaders(); 
    // now close any remaining streams. 
    synchronized (closeables) { 
     Set<Closeable> keys = closeables.keySet(); 
     for (Closeable c : keys) { 
      try { 
       c.close(); 
      } catch (IOException ioex) { 
       errors.add(ioex); 
      } 
     } 
     closeables.clear(); 
    } 
    if (errors.isEmpty()) { 
     return; 
    } 
    IOException firstex = errors.remove(0); 
    // Suppress any remaining exceptions 
    for (IOException error: errors) { 
     **firstex.addSuppressed(error);** 
    } 
    throw firstex; 
} 

Nói chung, cách tiếp cận như vậy có thể được sử dụng trong công việc hàng loạt (thao tác hàng loạt), khi chúng ta nên tiến tới mục tiếp theo (đóng cửa suối tiếp theo mở như trong ví dụ này) bất kể hoạt động trên mục hiện tại có thành công hay không.Theo cách này, chúng tôi có như tôi đã nói trước đây, theo cách nào đó, thực hiện song song có thể tạo ngoại lệ, trong đó bị chặn. Trong những trường hợp như vậy, chúng ta nên sử dụng cách tiếp cận ở trên để ném vào ngoại lệ với ngoại lệ bị loại bỏ còn lại trong đó.

+1

Tôi đã tìm thấy http://stackoverflow.com/questions/7860137/what-is-the-java-7-try-with-resources-bytecode-equivalent-using-try-catch-finall làm giải thích rõ ràng về cách thử -Với tính năng tài nguyên thực sự được triển khai. – alexsmail

+1

Là bắt ** (Ngoại lệ e) {ném e; } ** thực sự cần thiết trong mã đầu tiên của bạn? – MaKri

1

Trường hợp ngoại lệ bị loại trừ sẽ được lưu nếu mã thực thi trong khối cuối cùng sẽ ném ngoại lệ. Đó là một ngoại lệ đã xảy ra mà bạn có thể không quan tâm. Trong Java 6 như một ngoại lệ trong một khối cuối cùng sẽ trở thành ngoại lệ duy nhất mã gọi của bạn sẽ thấy nhưng với khối try-with-resource mới, mã gọi của bạn sẽ thấy ngoại lệ ban đầu và ngoại lệ xảy ra trong khối cuối cùng ảo sẽ là trong getSuppressed().

Trong trường hợp của bạn, chỉ cần giữ nguyên ngoại lệ ban đầu là nguyên nhân của ngoại lệ mới của bạn.

+1

bằng cách cơ bản đăng lại những gì có trong javadoc, bạn đang khuyến khích mọi người đăng bài đầu tiên và suy nghĩ sau/không bao giờ. – jtahlborn

+0

Vâng, tôi không biết về tính năng mới "thử-với-tài nguyên" trong JDK 1.7. Bắt đầu đọc về nó. Cảm ơn. – alexsmail

+0

@jtahlborn, làm thế nào tôi nên hình dung rằng tôi phải đọc phương thức 'printStackTrace()' http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#printStackTrace%28% 29? Tôi không thú vị trong công cụ theo dõi ngăn xếp ngay bây giờ. Đối với tôi, không có kết nối giữa các vấn đề. – alexsmail

Các vấn đề liên quan