Sonunda bir blok her zaman çalışır mı?


112

Sonunda java'da çalışmayabilecek herhangi bir koşul var mı? Teşekkürler.


13
Bu, tanınmış bir şirkette iş bulmaya çalışırken size sorulabilecek bir soru mu?
Tom Hawtin - tackline

@ TomHawtin-tackline adını vermek bakım? (Tanrım, bu gönderinin kaç yaşında olduğunu özledim!)
Hele

6
@Hele oyunu başkasına vermek istemezdim, ama google da yapabilirsin.
Tom Hawtin - tackline

kısa cevap: evet, normal koşullar altında.
Köpekbalığı

Yanıtlar:


139

dan Güneş Rehberler

Not: Try veya catch kodu yürütülürken JVM'den çıkılırsa, final bloğu çalışmayabilir. Benzer şekilde, dene ya da yakala kodunu yürüten iş parçacığı kesintiye uğrarsa ya da öldürülürse, uygulama bir bütün olarak devam etse bile final bloğu yürütülemeyebilir.

Nihayet bloğunun uygulanmayacağı başka yollar bilmiyorum ...


6
@dhiller - "Kapatma" nın "JVM çıkarsa ..." bölümüne dahil edildiğinden oldukça eminim :-p
Jason Coco

2
@Jason Coco: Feshetmek (güç kaybı durumunda olduğu gibi) çıkmakla aynı şey değil; ikincisi, ilki ile sonuçlanan az ya da çok organize bir süreçtir. ; p
user359996

2
AFAIK, bir iş parçacığı kesintiye uğrarsa, hemen durdurulmaz. Kesintiyi algılamak ve görevini durdurmak iş parçacığındaki koda bağlıdır, bu nedenle kodun çalışması gerekir.
Bart van Heukelom

2
Sanırım nihayet blokta bir istisna atılırsa, bloğun geri kalanı çalıştırılmaz.
Adriaan Koster

iyi bu berbat!
eiran

63

System.exit , Sanal Makineyi kapatır.

Şu anda çalışan Java Virtual Machine'i sonlandırır. Argüman bir durum kodu görevi görür; kural olarak, sıfırdan farklı bir durum kodu anormal sonlandırmayı gösterir.

Bu yöntem exit, sınıftaki yöntemi çağırır Runtime. Bu yöntem asla normal şekilde geri dönmez.

    try {
        System.out.println("hello");
        System.exit(0);
    }
    finally {
        System.out.println("bye");
    } // try-finally

"güle güle" yukarıdaki kodda yazdırılmaz.


Ayrıca bir istisna, Java Sanal Makinesi'ni kapatmalıdır.
kaissun

3
System.exit (0) yürütülürken bir İstisna oluşursa, sonunda blok yürütülecektir.
Halil

50

Sadece başkalarının söylediklerini genişletmek için, JVM'nin çıkması gibi bir şeye neden olmayan herhangi bir şey, nihayet engellenmesine neden olacaktır. Yani aşağıdaki yöntem:

public static int Stupid() {
  try {
    return 0;
  }
  finally {
    return 1;
  }
}

garip bir şekilde hem derleyecek hem de 1 döndürecektir.


2
Bu, birkaç hafta önce birkaç saat kafamı karıştırdı.
nickf

3
Nihayet bloğundan bir değer döndürmek kötü bir fikir olarak kabul edilir. Ya sadece try bloğundan dönün ya da try / final bloğunun dışından dönün. Çoğu IDE bunu bir uyarı ile işaretleyecektir.
Ran Biron

1
@nickf Artık kafanızın karışmadığını anlıyorum. 1'in neden 0'ın değil de döndürüldüğünün mekaniğini açıklar mısınız? Sadece başlangıçta 0 tutan fonksiyonun dönüş değerini depolayan belleğin (veya bir kayıt mı), en sonunda blok çalıştırıldığında üzerine yazıldığını tahmin edebilirim. .
Yaneeve

2
Bu ilginç, C # 'da nihayet bloktan dönmesine izin verilmez.
JMCF125

3
@RanBiron Elbette. Aslında bir nihayet bloğunun içine geri dönmeyi önermiyordu, sadece bir return ifadesinin bile söz konusu bloktaki kodun çalıştırılmasına neden olacağını göstermeye çalışıyordu.
Aquarelle

15

System.exit ile ilgili olarak, bir nihayet bloğunun yürütülemeyebileceği belirli yıkıcı hata türleri de vardır. JVM'nin belleği tamamen tükenirse, yakalanmadan çıkabilir veya sonunda gerçekleşebilir.

Özellikle aptalca kullanmaya çalıştığımız bir projeyi hatırlıyorum

catch (OutOfMemoryError oome) {
    // do stuff
}

Bu işe yaramadı çünkü JVM'de catch bloğunu yürütmek için bellek kalmamıştı.


OutOfMemoryError atıldığında, genellikle çok fazla bellek kalır (GC atmayı durdurmak için). Ancak, tekrar tekrar yakalarsanız, açıkça GC thrashing'e geri döneceksiniz.
Tom Hawtin - tackline

Kontrol edilmeyen istisnaların yakalanmaması gerektiğini düşündüm!
Sergii Shevchyk

1
Kendi tarafımda jdk7 kullanarak denedim, ancak OutOfMemory Hatası yakaladı!
Jaskey

10
try { for (;;); } finally { System.err.println("?"); }

Bu durumda, nihayet çalıştırılmayacaktır (kullanımdan kaldırılan Thread.stopçağrılmadıkça veya bir eşdeğeri, örneğin bir araçlar arayüzü aracılığıyla).


Bu sayfa bir ThreadDeath hatasının atıldığını ve Thread.stop () çağrıldığında yığının normal olarak çözüldüğünü iddia ediyor. Kaçırdığım bir sorun var mı? download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/guide/…
spurserh

Bir sorun olduğunu sanmıyorum. Belki orada olmayan bir yakalama hayal ediyorsunuzdur. Açık olarak koyarsak throw, finallyblok beklendiği gibi çalışacaktır. try { throw new ThreadDeath(); } finally { System.err.println("?"); }
Tom Hawtin - tackline

9

Sun öğreticisi, bu ileti dizisinde yanlış bir şekilde alıntılanmıştır.

Not: deneyin veya catch kod yürütülürken JVM çıkışlar, daha sonra nihayet blok halinde olacaktır yürütmüyor. Deneyin veya catch kod yürütme iş parçacığı kesintiye veya öldürülürse Aynı şekilde, nihayet blok olacak bir bütün olarak uygulama devam etse bile yürütmüyor.

Nihayet engellenmesi için güneş eğitimine yakından bakarsanız, "çalıştırılmayacak" ancak "çalıştırılamayabilir" demiyor. İşte doğru açıklama

Not: deneyin veya catch kod yürütülürken JVM çıkışlar, daha sonra nihayet blok halinde olabilir yürütmüyor. Deneyin veya catch kod yürütme iş parçacığı kesintiye veya öldürülürse Aynı şekilde, nihayet blok olabilir bir bütün olarak uygulama devam etse bile yürütmüyor.

Bu davranışın görünürdeki nedeni, system.exit () çağrısının, jvm'yi kapatmak için zaman alabilen bir çalışma zamanı sistem iş parçacığında işlenmesi, bu arada iş parçacığı zamanlayıcının en sonunda yürütmeyi isteyebilmesidir. Yani nihayet her zaman çalıştırmak için tasarlanmıştır, ancak jvm'yi kapatıyorsanız, jvm nihayet yürütülmeden önce kapanabilir.


6

Ayrıca trybloğun içinde bir kilitlenme / canlanma meydana gelirse .

İşte bunu gösteren kod:

public class DeadLocker {
    private static class SampleRunnable implements Runnable {
        private String threadId;
        private Object lock1;
        private Object lock2;

        public SampleRunnable(String threadId, Object lock1, Object lock2) {
            super();
            this.threadId = threadId;
            this.lock1 = lock1;
            this.lock2 = lock2;
        }

        @Override
        public void run() {
            try {
                synchronized (lock1) {
                    System.out.println(threadId + " inside lock1");
                    Thread.sleep(1000);
                    synchronized (lock2) {
                        System.out.println(threadId + " inside lock2");
                    }
                }
            } catch (Exception e) {
            } finally {
                System.out.println("finally");
            }
        }

    }

    public static void main(String[] args) throws Exception {
        Object ob1 = new Object();
        Object ob2 = new Object();
        Thread t1 = new Thread(new SampleRunnable("t1", ob1, ob2));
        Thread t2 = new Thread(new SampleRunnable("t2", ob2, ob1));
        t1.start();
        t2.start();
    }
}

Bu kod aşağıdaki çıktıyı üretir:

t1 inside lock1
t2 inside lock1

ve "nihayet" asla yazdırılmaz


3
Teknik olarak, try bloğu asla çıkmaz, bu nedenle nihayet bloğu hiçbir zaman yürütme şansı bulamamalıdır. Aynı şey sonsuz bir döngü için de söylenebilir.
Jeff Mercado

6

Try veya catch kodu çalıştırılırken JVM çıkarsa, final bloğu çalışmayabilir. ( kaynak )

Normal Kapatma - bu, arka plan programı olmayan son iş parçacığı çıktığında VEYA Runtime.exit () ( kaynak ) olduğunda gerçekleşir

Bir evre çıkış yaptığında, JVM çalışan evrelerin bir envanterini gerçekleştirir ve geriye kalan tek evreler arka plan programı evreleri ise, düzenli bir kapatma başlatır. JVM durduğunda, kalan tüm arka plan programı evreleri terk edilir ve sonunda bloklar çalıştırılmaz, yığınlar çözülmez, JVM'den çıkılır. Daemon iş parçacıkları idareli kullanılmalıdır, çok az işleme faaliyeti herhangi bir zamanda temizlik olmadan güvenle terk edilebilir. Özellikle, her tür G / Ç gerçekleştirebilecek görevler için daemon evrelerini kullanmak tehlikelidir. Daemon iş parçacıkları, bir bellek içi önbellekten süresi dolan girdileri düzenli olarak kaldıran bir arka plan iş parçacığı gibi "temizlik" görevleri için en iyi şekilde kaydedilir. ( kaynak )

Son arka plan programı olmayan iş parçacığı örneği:

public class TestDaemon {
    private static Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("Is alive");
                    Thread.sleep(10);
                    // throw new RuntimeException();
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                System.out.println("This will never be executed.");
            }
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread daemon = new Thread(runnable);
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(100);
        // daemon.stop();
        System.out.println("Last non-daemon thread exits.");
    }
}

Çıktı:

Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive

1

Aşağıdaki durumlarda, nihayet bloğu yürütülmeyecektir: -

  • Bloktan ne zaman System.exit(0)çağrılır try.
  • JVM'de bellek kalmadığında
  • Java işleminiz görev yöneticisi veya konsoldan zorla öldürüldüğünde
  • Senin kilitlenme koşulu trybloğu
  • Makineniz elektrik kesintisi nedeniyle kapandığında

Nihayet bloğunun uygulanmayacağı başka sınır durumlar da olabilir.


1

Sonunda blok kodu yürütmeyi durdurmanın iki yolu vardır:
1. System.exit () kullanın;
2. Bir şekilde yürütme kontrolü bloğu denemek için ulaşmazsa.
Görmek:

public class Main
{
  public static void main (String[]args)
  {
    if(true){
        System.out.println("will exceute");
    }else{
        try{
            System.out.println("result = "+5/0);
        }catch(ArithmeticException e){
          System.out.println("will not exceute");
        }finally{
          System.out.println("will not exceute");  
        }
    }
  }
}

0

Özellikle oyun çerçevesiyle ilgili olarak yürütülmeyen son blokun çok özel bir durumuna rastladım.

Bu denetleyici eylem kodundaki en sonunda bloğunun yalnızca bir İstisnadan sonra çağrıldığını, ancak çağrı gerçekten başarılı olduğunda asla çağrılmadığını görünce şaşırdım.

try {
    InputStream is = getInputStreamMethod();
    renderBinary(is, "out.zip");
catch (Exception e) {
    e.printStackTrace();
} finally {
    cleanUp();
}

Belki iş parçacığı sonlandırılır veya renderBinary () çağrıldığında başka bir şey olabilir. Aynı şeyin diğer render () çağrıları için de gerçekleştiğinden şüphelenirdim, ancak doğrulamadım.

RenderBinary () 'yi try / catch sonrasına taşıyarak problemi çözdüm. Daha fazla araştırma, oynatmanın, bir denetleyici eylemi yürütüldükten sonra yürütülen bir yöntem oluşturmak için bir @Finally ek açıklaması sağladığını ortaya çıkardı. Buradaki uyarı, bunun denetleyicideki HERHANGİ bir eylemin gerçekleştirilmesinden sonra çağrılacağıdır, bu nedenle her zaman iyi bir seçim olmayabilir.


-1
//If ArithmeticException Occur Inner finally would not be executed
class Temp
{
    public static void main(String[] s)
    {
        try
        {
        int x = 10/s.length;
        System.out.println(x);
        try
            {
                int z[] = new int[s.length];
                z[10] = 1000;
            }catch(ArrayIndexOutOfBoundsException e)
            {
                System.out.println(e);
            }
         finally
        {
            System.out.println("Inner finally");
        }
        }
        catch(ArithmeticException e)
        {
            System.out.println(e);
        }
    finally 
    {
        System.out.println("Outer Finally"); 
    }

System.out.println("Remaining Code");   
}
}

Girintiyi iyileştirin ve bazı ayrıntılar ekleyin.
ROMANIA_engineer

1
Yürütme, iç deneme bloğuna bile ulaşamazdı, tabii ki içsel nihayet yürütülmezdi.
Anton Arhipov
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.