Yakalama ve son olarak maddeye atılan istisna


155

Üniversitede Java ile ilgili bir soru üzerine, bu kod snippet'i vardı:

class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}

public class C1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.print(1);
            q();
        }
        catch (Exception i) {
            throw new MyExc2();
        }
        finally {
            System.out.print(2);
            throw new MyExc1();
        }
    }

    static void q() throws Exception {
        try {
            throw new MyExc1();
        }
        catch (Exception y) {
        }
        finally {
            System.out.print(3);
            throw new Exception();
        }
    }
}

Çıktısını vermem istendi. 13Exception in thread main MyExc2Cevap verdim , ama doğru cevap 132Exception in thread main MyExc1. Bu neden öyle? Nereye MyExc2gittiğini anlayamıyorum .

Yanıtlar:


167

Cevabınızı okumaya ve bunun nasıl ortaya çıkacağını görmeye dayanarak, "devam eden bir istisna" nın "önceliğe" sahip olduğunu düşündüğünüze inanıyorum. Aklında tut:

Bir catch bloğuna veya son olarak bu bloktan yayılacak bir bloğa yeni bir istisna atıldığında , yeni istisna dışa doğru yayıldıkça geçerli istisna iptal edilir (ve unutulur). Yeni istisna, diğer tüm istisnalar gibi yığını kaldırmaya başlar, geçerli bloktan çıkarılır (yakalama veya son olarak engelleme) ve geçerli herhangi bir yakalamaya veya son olarak yol boyunca bloklara maruz kalır.

Not uygulanabilir catch veya nihayet blokları içerir:

Bir catch bloğuna yeni bir istisna atıldığında, yeni istisna hala varsa bu catch'in nihayet bloğuna tabidir.

Şimdi, her vurduğunuzda throwgeçerli istisnayı izlemeyi bırakmanız ve yeni istisnayı izlemeye başlamanız gerektiğini hatırlayarak yürütmeyi tekrar izleyin .


7
«Cevabınızı okumaya ve bunun nasıl ortaya çıkacağını görmeye dayanarak," devam etmekte olan istisna "nın" önceliğe "sahip olduğunu düşündüğünüze inanıyorum» Teşekkür ederim ... tam da benim düşüncemdi :)
Jubstuff

39

Bu nedir Vikipedi nihayet maddesi hakkında şunları söylüyor:

Daha yaygın olanı, bir istisnanın meydana gelip gelmediği, tipik olarak istisna işleme bloğunun gövdesi içinde edinilen kaynakları serbest bırakmak için yürütülen ilgili bir maddedir (nihayet ya da emin olun).

Programınızı inceleyelim.

try {
    System.out.print(1);
    q();
}

Böylece, 1ekrana çıkılacak, sonra q()çağrılır. In q(), bir istisna atılır. İstisna sonra yakalanır Exception yama hiçbir şey yapmaz. Sonunda bir son madde yürütülür (zorunludur), böylece 3ekrana yazdırılır. (Yöntemde q(), nihayet maddesinde atılan bir istisna var , ayrıca q()yöntem istisnayı üst yığına geçirir ( throws Exceptionyöntem bildiriminde tarafından) new Exception()atılır ve yakalanır catch ( Exception i ), MyExc2istisna atılır (şimdilik istisna yığınına eklenir) ), ancak bir nihayet içinde mainbloğun ilk yürütülecektir.

Yani,

catch ( Exception i ) {
    throw( new MyExc2() );
} 
finally {
    System.out.print(2);
    throw( new MyExc1() );
}

Bir sonunda hüküm (hatırlamak, sadece yakaladım ... denir Exception ive atılan MyExc2) özünde, 2ekranda yazdırılır ... ve sonra 2ekrana yazdırılacak, bir MyExc1istisnası atılır. yöntemi MyExc1ile ele alınır public static void main(...).

Çıktı:

"Ana MyExc1 iş parçacığında 132 özel durum"

Öğretim üyesi doğru! :-)

Özünde bir varsa, nihayet bir deneme / yakalama yan tümcesinde, bir nihayet (yürütülecektir sonra özel durumu yakalamak önce yakalandı istisna dışında atma)


catchBeri yürütülen q()bir attı Exceptionkendi gelen finallybloğun.
Péter Török

"Q () öğesinde bir istisna atılır, ancak istisna tamamen atılmadan önce, son olarak bir yan tümce yürütülür, bu nedenle 3 ekrana yazdırılır." Ee ... hayır, atılan ilk istisna q, boş catchbloğu qiçeri (bu istisnayı yutar), sonra finallybloğa q. Dedi sonunda blok baskıları 3, daha sonra yeni bir istisna atar, ki bu sayesinde q's throws Exceptionyığına ebeveynine geçirilir.
Powerlord

38

Nihayet bloktaki istisnalar, catch bloğundaki istisnaların yerine geçer.

Java Language Specification 14 sürümünden alıntı :

Yakalama bloğu R nedeni nedeniyle aniden tamamlanırsa, son blok yürütülür. Sonra bir seçenek var:

  • Nihayet blok normal şekilde tamamlanırsa, try ifadesi R nedeni için aniden tamamlanır.

  • Sonunda blok S nedeni için aniden tamamlanırsa, try ifadesi S nedeni için aniden tamamlanır (ve R nedeni atılır).


21

Son olarak, try / catch bloğundaki herhangi bir yerden istisna atıldığında bile yan tümce yürütülür.

Çünkü son icra edilen mainve bir istisna atıyor, bu arayanların gördüğü istisna.

Bu nedenle, finallymaddenin herhangi bir şey atmadığından emin olmanın önemi , çünkü trybloktaki istisnaları yutabilir .


5
Ayrıca, try / catch bloğuna atılan bir istisna yoksa EVEN yürütülür
nanda

2
+1: Doğrudan ve OP'nin zaten anladığı görünen yığını yığılmadan noktaya.
Powerlord

9

A aynı anda iki istisna methodolamaz throw. Her zaman en son atılanı atar, exceptionbu durumda her zaman finallybloktan olanı olacaktır .

q()Metoddan ilk istisna atıldığında, yakalanacak ve sonunda atılan istisna tarafından yutulacaktır.

q () -> atılan new Exception -> main catch Exception -> throw new Exception -> finally yeni bir atış yapın exception(ve catch"kayıp")


3

Bunu düşünmenin en kolay yolu, geçerli istisnayı barındıran tüm uygulama için küresel bir değişken olduğunu hayal etmektir.

Exception currentException = null;

Her özel durum atılırken, "currentException" bu özel duruma ayarlanır. Uygulama sona erdiğinde, currentException! = Null olursa, çalışma zamanı hatayı bildirir.

Ayrıca, nihayet bloklar her zaman yöntem çıkmadan önce çalışır. Daha sonra kod snippet'ini:

public class C1 {

    public static void main(String [] argv) throws Exception {
        try {
            System.out.print(1);
            q();

        }
        catch ( Exception i ) {
            // <-- currentException = Exception, as thrown by q()'s finally block
            throw( new MyExc2() ); // <-- currentException = MyExc2
        }
        finally {
             // <-- currentException = MyExc2, thrown from main()'s catch block
            System.out.print(2);
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }

    }  // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console.

    static void q() throws Exception {
        try {
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }
        catch( Exception y ) {
           // <-- currentException = null, because the exception is caught and not rethrown
        }
        finally {
            System.out.print(3);
            throw( new Exception() ); // <-- currentException = Exception
        }
    }
}

Uygulamanın yürütme sırası:

main()
{
  try
    q()
    {
      try
      catch
      finally
    }
  catch
  finally
}

1

Sonunda blok denemek ve yakalamak sonra yürütülür ve her zaman yürütülür iyi bilinir .... Ama gördüğünüz gibi biraz zor bazen aşağıdaki bu kod snippet kontrol ve iade ve atış ifadeleri don olacak her zaman temasını beklediğimiz sırayla yapmaları gerekeni yapmazlar.

Şerefe.

/////////////Return dont always return///////

try{

    return "In Try";

}

finally{

    return "In Finally";

}

////////////////////////////////////////////


////////////////////////////////////////////    
while(true) { 

    try {

        return "In try";

   } 

   finally{

        break;     

    }          
}              
return "Out of try";      
///////////////////////////////////////////


///////////////////////////////////////////////////

while (true) {     

    try {            

        return "In try";    

     } 
     finally {   

         continue;  

     }                         
}
//////////////////////////////////////////////////

/////////////////Throw dont always throw/////////

try {

    throw new RuntimeException();

} 
finally {

    return "Ouuuups no throw!";

}
////////////////////////////////////////////////// 

1
class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}

public class C1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.print("TryA L1\n");
            q();
            System.out.print("TryB L1\n");
        }
        catch (Exception i) {
            System.out.print("Catch L1\n");                
        }
        finally {
            System.out.print("Finally L1\n");
            throw new MyExc1();
        }
    }

    static void q() throws Exception {
        try {
            System.out.print("TryA L2\n");
            q2();
            System.out.print("TryB L2\n");
        }
        catch (Exception y) {
            System.out.print("Catch L2\n");
            throw new MyExc2();  
        }
        finally {
            System.out.print("Finally L2\n");
            throw new Exception();
        }
    }

    static void q2() throws Exception {
        throw new MyExc1();
    }
}

Sipariş:

TryA L1
TryA L2
Catch L2
Finally L2
Catch L1
Finally L1        
Exception in thread "main" MyExc1 at C1.main(C1.java:30)

https://www.compilejava.net/


1
Bu kod snippet'i çözüm olsa da, bir açıklama da dahil olmak üzere mesajınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı unutmayın ve bu insanlar kod önerinizin nedenlerini bilmiyor olabilir
Rahul Gupta

1

Mantık baskı bitinceye kadar açıktır 13. Sonra atılmış istisna q()tarafından yakalanır catch (Exception i)içinde main()ve bir new MyEx2()atılır hazırdır. Ancak, istisnayı atmadan önce finallybloğun ilk önce yürütülmesi gerekir. Sonra çıktı olur 132ve finallybaşka bir istisna atılmasını ister new MyEx1().

Bir yöntem birden fazla Exceptionatamadığı için her zaman en sonuncuyu atacaktır Exception. Her iki Başka bir deyişle, catchve finallybloklar atmak deneyin Exception, sonra Exceptionmandalı olan yuttu ve sadece istisna finallyatılmış olacaktır.

Böylece, bu programda, İstisna MyEx2yutulur ve MyEx1atılır. Bu İstisna atılır main()ve artık yakalanmaz, böylece JVM durur ve son çıktı olur 132Exception in thread main MyExc1.

Eğer bir varsa özünde, finallybir de try/catchfıkra, bir finallyçalıştırılacaktır özel durumu yakalamak SONRA , ancak herhangi yakalandı durum atma ÖNCE , ve SADECE en son istisna sonunda atılmış olacaktır .


0

Bence sadece finallyblokları yürümek gerekiyor :

  1. "1" yazdırın.
  2. finallyiçinde q"3" baskı.
  3. finallyiçinde main"2" baskı.

0

Bu tür bir durumla başa çıkmak, yani sonunda engellemenin istisnasını ele almak. Son olarak bloğu try block ile çevreleyebilirsiniz: Aşağıdaki örneğe python ile bakınız:

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print "Going to close the file"
      fh.close()
except IOError:
   print "Error: can\'t find file or read data"

-1

Bunun sorunu çözdüğünü düşünüyorum:

boolean allOk = false;
try{
  q();
  allOk = true;
} finally {
  try {
     is.close();
  } catch (Exception e) {
     if(allOk) {
       throw new SomeException(e);
     }
  }
}

3
Hangi sorunu "çözeceksiniz"? Sınavdaki soruyu mu kastediyorsunuz? iyi cevap verdi. Verilen kodun problemini kastediyorsanız, bu sadece bir sınav sorusu olduğundan, onu suçlamanın bir anlamı yoktur.
Dünya Motoru
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.