2014-09-01 3 views
5

से होने वाली कोशिशों के साथ प्रयासों में आत्म-दमन त्रुटि, मुझे एक परेशानी की स्थिति में आ गया है जहां मैं जावा को शिकायत करने की उम्मीद करता हूं (Throwable.addSuppressed से Throwable.addSuppressed से) एक ही अपवाद को दो बार फेंकने के बारे में, एक बार कोशिश करने के भीतर- संसाधनों के ब्लॉक के साथ और AutoCloseable कक्षा के बंद() दिनचर्या से एक बार। मैंने नीचे एक साधारण परीक्षण केस बनाया है जो समस्या को हाइलाइट करता है।ग्रहण

मैं निम्नलिखित कोड के साथ JDK 1.7.0_65 चला रहा हूँ:

public class TestDoubleThrow { 
    public static void main(String[] args) { 
     class TestA implements AutoCloseable { 
      RuntimeException e; 
      public TestA(RuntimeException e) { this.e = e; } 
      @Override public void close() { throw e; } 
     } 

     RuntimeException e = new RuntimeException("My Exception"); 
     try (TestA A = new TestA(e)) { 
      throw e; 
     } 
    } 
} 

जब मैं संकलन और कमांड लाइन मैं उम्मीद परिणाम प्राप्त के माध्यम से उपरोक्त कोड चलाने के लिए, एक त्रुटि दिखाने मैं स्वयं करने की कोशिश की दबाने और अपवाद:

[coreys terminal]$ java TestDoubleThrow.java ; java TestDoubleThrow 
Exception in thread "main" java.lang.IllegalArgumentException: Self-suppression not permitted 
    at java.lang.Throwable.addSuppressed(Throwable.java:1043) 
    at TestDoubleThrow.main(TestDoubleThrow.java:12) 
Caused by: java.lang.RuntimeException: My Exception 
    at TestDoubleThrow.main(TestDoubleThrow.java:9) 

हालांकि, जब मैं का निर्माण और मैं एक ही परिणाम नहीं मिलता है ग्रहण से एक ही कोड चलाने के लिए, मैं निम्नलिखित मिल:

Exception in thread "main" java.lang.RuntimeException: My Exception 
    at TestDoubleThrow.main(TestDoubleThrow.java:9) 

मैंने आदेश पंक्ति से निर्माण के बाद .class पथ को हटा दिया ताकि यह सुनिश्चित किया जा सके कि ग्रहण ने इसे पुनर्निर्मित किया है। एक डीबगर से चल रहा मैंने देखा कि ग्रहण से कोड कभी भी java.lang.Throwable.addSuppressed() में प्रवेश नहीं करता है।

दिलचस्प बात यह है कि, यदि मैं ग्रहण से कक्षा का निर्माण करता हूं, तो उसे कमांड लाइन से चलाएं, मैं स्वयं दमन त्रुटि नहीं देखता हूं। इसी प्रकार यदि मैं कमांड लाइन से कक्षा का निर्माण करता हूं और इसे ग्रहण से चलाता हूं (एक्लिप्स से इमारत के बिना) तो मुझे त्रुटि दिखाई देती है। इससे पता चलता है कि कक्षा के निर्माण के बारे में कुछ मजाकिया है।

मैं यह जानना चाहता हूं कि ग्रहण इस तरह से कक्षा का निर्माण कैसे कर सकता है कि मुझे त्रुटि मिलती है, क्योंकि मेरे उद्देश्यों के लिए यह एक त्रुटि है और मैं इसे बनाने और चलाने के दौरान इसे पहचानने में सक्षम होना चाहता हूं ग्रहण से।

उत्तर

3

ग्रहण का अपना स्वयं का कंपाइलर है और यह विभिन्न आउटपुट का उत्पादन कर रहा है। ग्रहण जांच द्वारा संकलित कोड यह देखने के लिए कि क्या दबाने वाला अपवाद Throwable.addSuppressed को आमंत्रित करने से पहले स्वयं बराबर है या नहीं। आप इसे javap उपकरण का उपयोग करके देख सकते हैं।

ग्रहण कंपाइलर आउटपुट में if_acmpeq लाइन देखें।

जेडीके व्यवहार the example in the specification पर अधिक बारीकी से पालन करता है। ग्रहण टीम के साथ आप raise a defect कर सकते हैं।

JDK/javac उत्पादन:

public static void main(java.lang.String[]); 
    Code: 
     0: new   #2     // class java/lang/RuntimeException 
     3: dup   
     4: ldc   #3     // String My Exception 
     6: invokespecial #4     // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V 
     9: astore_1  
     10: new   #5     // class TestDoubleThrow$1TestA 
     13: dup   
     14: aload_1  
     15: invokespecial #6     // Method TestDoubleThrow$1TestA."<init>":(Ljava/lang/RuntimeException;)V 
     18: astore_2  
     19: aconst_null 
     20: astore_3  
     21: aload_1  
     22: athrow   
     23: astore  4 
     25: aload   4 
     27: astore_3  
     28: aload   4 
     30: athrow   
     31: astore  5 
     33: aload_2  
     34: ifnull  63 
     37: aload_3  
     38: ifnull  59 
     41: aload_2  
     42: invokevirtual #8     // Method TestDoubleThrow$1TestA.close:()V 
     45: goto   63 
     48: astore  6 
     50: aload_3  
     51: aload   6 
     53: invokevirtual #9     // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V 
     56: goto   63 
     59: aload_2  
     60: invokevirtual #8     // Method TestDoubleThrow$1TestA.close:()V 
     63: aload   5 
     65: athrow   
    Exception table: 
     from to target type 
      21 23 23 Class java/lang/Throwable 
      41 45 48 Class java/lang/Throwable 
      21 33 31 any 

ग्रहण उत्पादन:

public static void main(java.lang.String[]); 
    Code: 
     0: new   #16     // class java/lang/RuntimeException 
     3: dup   
     4: ldc   #18     // String My Exception 
     6: invokespecial #20     // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V 
     9: astore_1  
     10: aconst_null 
     11: astore_2  
     12: aconst_null 
     13: astore_3  
     14: new   #23     // class TestDoubleThrow$1TestA 
     17: dup   
     18: aload_1  
     19: invokespecial #25     // Method TestDoubleThrow$1TestA."<init>":(Ljava/lang/RuntimeException;)V 
     22: astore  4 
     24: aload_1  
     25: athrow   
     26: astore_2  
     27: aload   4 
     29: ifnull  37 
     32: aload   4 
     34: invokevirtual #28     // Method TestDoubleThrow$1TestA.close:()V 
     37: aload_2  
     38: athrow   
     39: astore_3  
     40: aload_2  
     41: ifnonnull  49 
     44: aload_3  
     45: astore_2  
     46: goto   59 
     49: aload_2  
     50: aload_3  
     51: if_acmpeq  59 
     54: aload_2  
     55: aload_3  
     56: invokevirtual #31     // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V 
     59: aload_2  
     60: athrow   
    Exception table: 
     from to target type 
      24 26 26 any 
      14 39 39 any 

मैं JDK 8 और ग्रहण 4.4 इस्तेमाल किया।

+0

मैंने दोनों मामलों में बाइट कोड को देखते समय एक समान चीज़ देखी। मुझे एक [जेडीके बग] (https://bugs.openjdk.java.net/browse/JDK-8042377) के रूप में चर्चा की गई बग मिली। चाहे वह एक जेडीके बग है या ग्रहण बग मेरे लिए नहीं है :) दोनों के बीच लगातार व्यवहार करना अच्छा होगा, और तथ्य ग्रहण वास्तव में कोड डालने वाला है जो थ्रोवेबल में उस महानता से नहीं है। – CoreyP