Apakah blok akhirnya selalu dijalankan di Jawa?

2382

Mempertimbangkan kode ini, dapatkah saya benar - benar yakin bahwa finallyblok selalu dijalankan, tidak peduli apa something()itu?

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}
jonny lima
sumber
473
Jika tidak, kata kunci yang harus dinamai probably.
Noon Silk
4
kemungkinan duplikat Di Jawa, apakah pengembalian truf akhirnya?
polygenelubricants
37
Tidak selalu
Boann
2
Java efektif mengatakan sebaliknya informit.com/articles/article.aspx?p=1216151&seqNum=7
Binoy Babu
27
@BinoyBabu, finalizer ! = finally; finalizer == finalize()metode.
jaco0646

Jawaban:

2699

Ya, finallyakan dipanggil setelah eksekusi blok kode tryatau catch.

Satu-satunya waktu finallytidak akan dipanggil adalah:

  1. Jika Anda memohon System.exit()
  2. Jika Anda memohon Runtime.getRuntime().halt(exitStatus)
  3. Jika JVM crash terlebih dahulu
  4. Jika JVM mencapai loop infinite (atau beberapa pernyataan non-interruptable lainnya) di blok tryataucatch
  5. Jika OS secara paksa menghentikan proses JVM; mis. kill -9 <pid>pada UNIX
  6. Jika sistem host mati; misalnya, kegagalan daya, kesalahan perangkat keras, panik OS, dan lain-lain
  7. Jika finallyblok akan dieksekusi oleh thread daemon dan semua thread non-daemon lainnya keluar sebelum finallydipanggil
Jodonnell
sumber
44
Sebenarnya thread.stop()tidak selalu mencegah finallyblok dari dieksekusi.
Piotr Findeisen
181
Bagaimana kalau kita mengatakan bahwa finallyblok akan dipanggil setelah itu tryblok, dan sebelum kontrol lolos ke pernyataan berikut. Itu konsisten dengan blok coba yang melibatkan loop tak terbatas dan karenanya blok akhirnya tidak pernah benar-benar dipanggil.
Andrzej Doyle
9
ada juga kasus lain, ketika kita menggunakan blok try-catch-akhirnya
bersarang
7
juga, akhirnya blok tidak dipanggil jika ada pengecualian yang dilemparkan oleh daemon thread.
Amrish Pandey
14
@BinoyBabu - Itu tentang finalizer, bukan akhirnya blokir
avmohan
567

Kode contoh:

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int test() {
    try {
        return 0;
    }
    finally {
        System.out.println("finally trumps return.");
    }
}

Keluaran:

finally trumps return. 
0
Kevin
sumber
18
FYI: Dalam C # perilaku itu identik terlepas dari kenyataan bahwa mengganti pernyataan dalam finally-klik dengan return 2;tidak diperbolehkan (Kompiler-Kesalahan).
Alexander Pacha
15
Berikut adalah detail penting yang harus diperhatikan: stackoverflow.com/a/20363941/2684342
WoodenKitty
18
Anda bahkan dapat menambahkan pernyataan kembali di blok terakhir itu sendiri, yang kemudian akan menimpa nilai kembali sebelumnya. Ini juga secara ajaib membuang pengecualian yang tidak ditangani. Pada titik itu, Anda harus mempertimbangkan refactoring kode Anda.
Zyl
8
Itu tidak benar-benar membuktikan bahwa akhirnya truf kembali. Nilai kembali dicetak dari kode pemanggil. Sepertinya tidak terbukti banyak.
Trimtab
20
Maaf, tapi ini demonstrasi bukan bukti. Ini hanya bukti jika Anda dapat menunjukkan bahwa contoh ini selalu berlaku seperti ini di semua platform Java, DAN bahwa contoh serupa juga selalu berlaku seperti ini.
Stephen C
391

Juga, meskipun itu praktik yang buruk, jika ada pernyataan pengembalian di dalam blok akhirnya, itu akan mengalahkan pengembalian lain dari blok biasa. Artinya, blok berikut ini akan kembali salah:

try { return true; } finally { return false; }

Hal yang sama dengan melempar pengecualian dari blok terakhir.

MooBob42
sumber
95
Ini adalah praktik yang BENAR-BENAR buruk. Lihat stackoverflow.com/questions/48088/... untuk info lebih lanjut tentang mengapa ini buruk.
John Meagher
23
Sepakat. Pengembalian dalam akhirnya {} mengabaikan setiap pengecualian yang dilontarkan dalam percobaan {}. Mengerikan!
neu242
8
@ dominicbri7 Mengapa Anda pikir ini praktik yang lebih baik? Dan mengapa harus berbeda ketika fungsi / metode batal?
corsiKa
8
Untuk alasan yang sama saya TIDAK PERNAH menggunakan goto dalam kode C ++ saya. Saya pikir banyak pengembalian membuatnya lebih sulit untuk dibaca dan lebih sulit untuk debug (tentu saja dalam kasus yang sangat sederhana itu tidak berlaku). Saya kira itu hanya preferensi pribadi dan pada akhirnya Anda dapat mencapai hal yang sama menggunakan metode mana pun
dominicbri7
16
Saya cenderung menggunakan sejumlah pengembalian ketika beberapa kasus luar biasa terjadi. Seperti jika (ada alasan untuk tidak melanjutkan) kembali;
iHearGeoff
257

Inilah kata-kata resmi dari Spesifikasi Bahasa Jawa.

14.20.2. Eksekusi try-akhirnya dan try-catch-akhirnya

Sebuah trypernyataan dengan finallyblok dijalankan dengan terlebih dahulu mengeksekusi tryblok. Lalu ada pilihan:

  • Jika eksekusi tryblok selesai secara normal, [...]
  • Jika eksekusi tryblok selesai tiba-tiba karena thrownilai V , [...]
  • Jika eksekusi tryblok selesai tiba-tiba karena alasan lain R , maka finallyblok dieksekusi. Lalu ada pilihan:
    • Jika akhirnya blok Rampungkan normal, maka trypernyataan melengkapi tiba-tiba karena alasan R .
    • Jika finallyblok selesai tiba-tiba karena alasan S , maka trypernyataan lengkap tiba-tiba karena alasan S ( dan alasan R dibuang ).

Spesifikasi untuk returnsebenarnya membuat ini eksplisit:

JLS 14.17 Pernyataan pengembalian

ReturnStatement:
     return Expression(opt) ;

Sebuah returnpernyataan tanpa Expression upaya untuk mentransfer kontrol ke Invoker metode atau konstruktor yang berisi itu.

Sebuah returnpernyataan dengan Expression upaya untuk mentransfer kontrol ke Invoker dari metode yang berisi itu; nilai Expressionmenjadi nilai metode doa.

Deskripsi sebelumnya mengatakan " upaya untuk mentransfer kontrol " bukan hanya " transfer kontrol " karena jika ada trypernyataan dalam metode atau konstruktor yang trybloknya berisi returnpernyataan, maka setiap finallyklausa dari trypernyataan tersebut akan dieksekusi, dalam urutan, paling dalam ke luar , sebelum kontrol ditransfer ke penyerang metode atau konstruktor. Penyelesaian finallyklausa yang tiba-tiba dapat mengganggu transfer kendali yang dimulai oleh suatu returnpernyataan.

polygenelubricants
sumber
163

Selain tanggapan lain, penting untuk menunjukkan bahwa 'akhirnya' memiliki hak untuk menimpa setiap pengecualian / nilai yang dikembalikan oleh blok try..catch. Misalnya, kode berikut mengembalikan 12:

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

Demikian pula, metode berikut ini tidak membuang pengecualian:

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

Sementara metode berikut tidak membuangnya:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}
Eyal Schneider
sumber
63
Perlu dicatat bahwa kasus tengah justru merupakan alasan mengapa memiliki pernyataan pengembalian di dalam blok akhirnya benar-benar mengerikan (bisa menyembunyikan Throwable apa pun).
Dimitris Andreou
2
Siapa yang tidak mau yang tertekan OutOfMemoryError? ;)
RecursiveExceptionException
Saya mengujinya dan memang menekan kesalahan seperti itu (yipes!). Itu juga menghasilkan peringatan ketika saya mengkompilasinya (yay!). Dan Anda dapat bekerja di sekitar itu dengan mendefinisikan variabel kembali dan kemudian menggunakan return retVal setelah itu finallyblok, meskipun yang tentu saja mengasumsikan bahwa Anda ditekan beberapa pengecualian lain karena kode tidak akan masuk akal sebaliknya.
Maarten Bodewes
120

Saya mencoba contoh di atas dengan sedikit modifikasi-

public static void main(final String[] args) {
    System.out.println(test());
}

public static int test() {
    int i = 0;
    try {
        i = 2;
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
    }
}

Output kode di atas:

akhirnya truf kembali.
2

Ini karena ketika return i;dieksekusi imemiliki nilai 2. Setelah ini, finallyblok dieksekusi di mana 12 ditugaskan idan kemudian System.outdieksekusi.

Setelah mengeksekusi finallyblok, tryblok mengembalikan 2, bukannya mengembalikan 12, karena pernyataan pengembalian ini tidak dieksekusi lagi.

Jika Anda akan debug kode ini di Eclipse maka Anda akan mendapatkan perasaan bahwa setelah melaksanakan System.outdari finallyblok returnpernyataan tryblok dijalankan lagi. Tapi ini bukan masalahnya. Ini hanya mengembalikan nilai 2.

vibhash
sumber
10
Contoh ini mengagumkan, ia menambahkan sesuatu yang belum disebutkan di lusinan utas yang akhirnya terkait. Saya pikir hampir tidak ada pengembang yang tahu ini.
Semoga
4
Bagaimana jika iitu bukan primitif, tetapi objek Integer.
Yamcha
Saya kesulitan memahami kasus ini. docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.17 mengatakan bahwa, "Pernyataan pengembalian dengan Ekspresi mencoba untuk mentransfer kontrol ke penyerang metode atau badan lambda yang berisi itu .... Jika evaluasi Ekspresi selesai secara normal, menghasilkan nilai V .. "Apa yang bisa saya tebak dari pernyataan ini adalah- sepertinya pengembalian tidak mengevaluasi ekspresi lagi setelah mengevaluasi nilai V, itu sebabnya mengubah saya tidak memengaruhi nilai yang dikembalikan, koreksi saya.
meexplorer
Tetapi saya tidak dapat menemukan bukti mengenai hal ini, di mana disebutkan bahwa return tidak mengevaluasi ekspresi lagi.
meexplorer
1
@meexplorer agak terlambat, tetapi dijelaskan di JLS 14.20.2. Eksekusi try-akhirnya dan try-catch-akhirnya - kata agak rumit, 14,17. Pernyataan pengembalian juga harus dibaca
user85421
117

Inilah uraian jawaban Kevin . Penting untuk mengetahui bahwa ekspresi yang akan dikembalikan dievaluasi sebelumnya finally, bahkan jika itu dikembalikan setelah.

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int printX() {
    System.out.println("X");
    return 0;
}

public static int test() {
    try {
        return printX();
    }
    finally {
        System.out.println("finally trumps return... sort of");
    }
}

Keluaran:

X
finally trumps return... sort of
0
WoodenKitty
sumber
8
Penting untuk diketahui.
Aminadav Glickshtein
Bagus untuk tahu, dan masuk akal juga. Tampaknya benar-benar mengembalikan nilai pengembalian adalah apa yang terjadi setelahnya finally. Menghitung nilai kembali (di printX()sini) masih ada sebelum itu.
Albert
contoh yang baik dengan semua 3 poin "kembali"!
radistao
Nggak. Kode di atas harus diganti System.out.println("finally trumps return... sort of");denganSystem.out.print("finally trumps return in try"); return 42;
Pacerier
54

Itulah seluruh ide dari blok akhirnya. Ini memungkinkan Anda memastikan Anda melakukan pembersihan yang mungkin dilewati karena Anda kembali, antara lain, tentu saja.

Akhirnya dipanggil terlepas dari apa yang terjadi di blok coba ( kecuali jika Anda menelepon System.exit(int)atau Java Virtual Machine menendang untuk beberapa alasan lain).

Chris Cooper
sumber
Itu jawaban yang sangat lemah. stackoverflow.com/a/65049/715269
Gangnus
42

Cara logis untuk memikirkan ini adalah:

  1. Kode yang ditempatkan di blok akhirnya harus dijalankan apa pun yang terjadi di dalam blok coba
  2. Jadi, jika kode di blok percobaan mencoba mengembalikan nilai atau melemparkan pengecualian, item ditempatkan 'di rak' hingga blok akhirnya dapat dieksekusi
  3. Karena kode di blok terakhir memiliki (menurut definisi) prioritas tinggi dapat mengembalikan atau membuang apa pun yang disukainya. Dalam hal apa pun yang tersisa 'di rak' dibuang.
  4. Satu-satunya pengecualian untuk ini adalah jika VM dimatikan sepenuhnya selama blok coba misalnya dengan 'System.exit'
Garth Gilmour
sumber
10
Apakah ini hanya "cara logis untuk memikirkannya" atau apakah benar-benar bagaimana blok akhirnya dimaksudkan untuk bekerja sesuai dengan spesifikasi? Tautan ke sumber daya Sun akan sangat menarik di sini.
matias
21

akhirnya selalu dieksekusi kecuali ada penghentian program yang tidak normal (seperti memanggil System.exit (0) ..). jadi, sysout Anda akan dicetak

shyam
sumber
18

Blok akhirnya selalu dieksekusi kecuali ada penghentian program abnormal, baik yang disebabkan oleh crash JVM atau dari panggilan ke System.exit(0).

Selain itu, nilai apa pun yang dikembalikan dari dalam blok akhirnya akan menimpa nilai yang dikembalikan sebelum eksekusi blok akhirnya, jadi berhati-hatilah memeriksa semua titik keluar saat menggunakan coba akhirnya.

pengguna9189
sumber
18

Tidak, tidak selalu satu kasus pengecualian adalah // System.exit (0); sebelum akhirnya blok mencegah akhirnya dieksekusi.

  class A {
    public static void main(String args[]){
        DataInputStream cin = new DataInputStream(System.in);
        try{
            int i=Integer.parseInt(cin.readLine());
        }catch(ArithmeticException e){
        }catch(Exception e){
           System.exit(0);//Program terminates before executing finally block
        }finally{
            System.out.println("Won't be executed");
            System.out.println("No error");
        }
    }
}
Rajendra Jadi
sumber
Dan itulah salah satu alasan Anda benar-benar tidak boleh menelepon System.exit () ...
Franz D.
13

Akhirnya selalu dijalankan itulah intinya, hanya karena itu muncul dalam kode setelah pengembalian tidak berarti bahwa itulah yang diterapkan. Java runtime memiliki tanggung jawab untuk menjalankan kode ini saat keluar daritry blok.

Misalnya jika Anda memiliki yang berikut:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

Runtime akan menghasilkan sesuatu seperti ini:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

Jika eksepsi yang tidak tertangkap dilemparkan finallyblok akan berjalan dan eksepsi akan terus merambat.

Motti
sumber
11

Ini karena Anda menetapkan nilai i sebagai 12, tetapi tidak mengembalikan nilai i ke fungsi. Kode yang benar adalah sebagai berikut:

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}
Wasim
sumber
10

Karena blok akhirnya akan selalu dipanggil kecuali jika Anda menelepon System.exit()(atau utas macet).

Jay Riggs
sumber
10

Secara ringkas, dalam Dokumentasi Java resmi (Klik di sini ), tertulis bahwa -

Jika JVM keluar saat kode coba atau tangkap dijalankan, maka blok akhirnya mungkin tidak dapat dijalankan. Demikian juga, jika utas yang mengeksekusi kode coba atau tangkap terganggu atau terbunuh, blok akhirnya mungkin tidak dapat dijalankan meskipun aplikasi secara keseluruhan berlanjut.

bikz05
sumber
10

Jawabannya sederhana, YA .

MEMASUKKAN:

try{
    int divideByZeroException = 5 / 0;
} catch (Exception e){
    System.out.println("catch");
    return;    // also tried with break; in switch-case, got same output
} finally {
    System.out.println("finally");
}

KELUARAN:

catch
finally
Memenuhi
sumber
1
Jawabannya sederhana TIDAK.
Christophe Roussy
1
@ChristopheRoussy Bagaimana? Bisakah Anda jelaskan?
Bertemu
1
baca jawaban yang diterima, pertanyaan awal adalah tentang 'Akankah selalu dieksekusi' dan itu tidak akan selalu. Dalam kasus Anda itu akan tetapi ini tidak menjawab pertanyaan asli dan bahkan mungkin pemula yang menyesatkan.
Christophe Roussy
lalu dalam hal apa ia tidak akan dieksekusi?
Temui
Dalam semua kasus yang disebutkan dalam jawaban lain, lihat jawaban yang diterima dengan 1000+ upvotes.
Christophe Roussy
9

Ya itu akan dipanggil. Itulah inti dari akhirnya memiliki kata kunci. Jika melompat keluar dari blok coba / tangkap hanya bisa melewati blok akhirnya itu sama dengan menempatkan System.out.println di luar coba / tangkap.

Mendelt
sumber
9

Ya, akhirnya blok selalu dijalankan. Sebagian besar pengembang menggunakan blok ini untuk menutup koneksi database, objek resultset, objek pernyataan dan juga menggunakan hibernate java untuk mengembalikan transaksi.

Gautam Viradiya
sumber
9

TIDAK SELALU

The Java Bahasa spesifikasi menjelaskan bagaimana try- catch- finallydan try- catchblok bekerja di 14.20.2
Dalam tidak ada tempat itu menetapkan bahwa finallyblok selalu dieksekusi. Tetapi untuk semua kasus di mana try- catch- finallydan try- finallyblok menyelesaikannya tidak menentukan bahwa sebelum penyelesaian finallyharus dijalankan.

try {
  CODE inside the try block
}
finally {
  FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).

JLS tidak menjamin bahwa FIN dijalankan setelah KODE . JLS menjamin bahwa jika CODE dan NEXT dieksekusi maka FIN akan selalu dieksekusi setelah CODE dan sebelum NEXT .

Mengapa JLS tidak menjamin bahwa finallyblok selalu dieksekusi setelah tryblok? Karena itu tidak mungkin. Tidak mungkin tetapi mungkin bahwa JVM akan dibatalkan (membunuh, crash, matikan) setelah menyelesaikan tryblok tetapi sebelum eksekusifinally blok. Tidak ada yang bisa dilakukan JLS untuk menghindari ini.

Dengan demikian, setiap perangkat lunak yang untuk perilaku yang tepat tergantung pada finallyblok yang selalu dieksekusi setelah tryblok mereka selesai disadap.

returninstruksi dalam tryblok tidak relevan dengan masalah ini. Jika eksekusi mencapai kode setelah try- catch- finallydijamin bahwa finallyblok akan dieksekusi sebelumnya, dengan atau tanpa returninstruksi di dalam tryblok.

Pengecut Anonim
sumber
8

Ya, tentu saja. Apa pun yang terjadi dalam blok coba atau tangkap Anda kecuali jika System.exit () dipanggil atau JVM lumpuh. jika ada pernyataan kembali di blok, akhirnya akan dieksekusi sebelum pernyataan kembali itu.

Karthikeyan
sumber
8

Ya, tentu saja. Satu-satunya hal yang tidak akan terjadi adalah JVM keluar atau macet

abhig
sumber
8

Menambahkan ke jawaban @ vibhash karena tidak ada jawaban lain yang menjelaskan apa yang terjadi dalam kasus objek yang bisa berubah seperti di bawah ini.

public static void main(String[] args) {
    System.out.println(test().toString());
}

public static StringBuffer test() {
    StringBuffer s = new StringBuffer();
    try {
        s.append("sb");
        return s;
    } finally {
        s.append("updated ");
    }
}

Akan menghasilkan

sbupdated 
Pradeep Kumaresan
sumber
Pada Java 1.8.162, ini bukan output.
Sam
8

Saya mencoba ini, ini adalah utas tunggal.

public static void main(String args[]) throws Exception {
    Object obj = new Object();
    try {
        synchronized (obj) {
            obj.wait();
            System.out.println("after wait()");
        }
    } catch (Exception ignored) {
    } finally {
        System.out.println("finally");
    }
}

The main Threadakan berada di waitnegara selamanya, maka finallytidak akan pernah disebut ,

jadi output konsol tidak akan print String: setelah wait()ataufinally

Setuju dengan @Stephen C, contoh di atas adalah salah satu dari 3 kasus yang disebutkan di sini :

Menambahkan beberapa kemungkinan loop tak terhingga dalam kode berikut:

// import java.util.concurrent.Semaphore;

public static void main(String[] args) {
    try {
        // Thread.sleep(Long.MAX_VALUE);
        // Thread.currentThread().join();
        // new Semaphore(0).acquire();
        // while (true){}
        System.out.println("after sleep join semaphore exit infinite while loop");
    } catch (Exception ignored) {
    } finally {
        System.out.println("finally");
    }
}

Kasus 2: Jika JVM crash terlebih dahulu

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public static void main(String args[]) {
    try {
        unsafeMethod();
        //Runtime.getRuntime().halt(123);
        System.out.println("After Jvm Crash!");
    } catch (Exception e) {
    } finally {
        System.out.println("finally");
    }
}

private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe) f.get(null);
    unsafe.putAddress(0, 0);
}

Ref: Bagaimana Anda menabrak JVM?

Kasus 6: Jika finallyblok akan dieksekusi oleh daemon Threaddan semua non-daemon Threadskeluar sebelumnyafinally dipanggil.

public static void main(String args[]) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                printThreads("Daemon Thread printing");
                // just to ensure this thread will live longer than main thread
                Thread.sleep(10000);
            } catch (Exception e) {
            } finally {
                System.out.println("finally");
            }
        }
    };
    Thread daemonThread = new Thread(runnable);
    daemonThread.setDaemon(Boolean.TRUE);
    daemonThread.setName("My Daemon Thread");
    daemonThread.start();
    printThreads("main Thread Printing");
}

private static synchronized void printThreads(String str) {
    System.out.println(str);
    int threadCount = 0;
    Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
    for (Thread t : threadSet) {
        if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
            System.out.println("Thread :" + t + ":" + "state:" + t.getState());
            ++threadCount;
        }
    }
    System.out.println("Thread count started by Main thread:" + threadCount);
    System.out.println("-------------------------------------------------");
}

output: Ini tidak mencetak "akhirnya" yang menyiratkan "Akhirnya blok" di "daemon thread" tidak dijalankan

main Thread Printing  
Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED  
Thread :Thread[main,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE   
Thread count started by Main thread:3  
-------------------------------------------------  
Daemon Thread printing  
Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE  
Thread count started by Main thread:2  
-------------------------------------------------  

Process finished with exit code 0
dkb
sumber
4
Lihat jawaban yang diterima. Ini hanya kasus tepi dari "loop tak terbatas".
Stephen C
8

Pertimbangkan program berikut:

public class SomeTest {

    private static StringBuilder sb = new StringBuilder();

    public static void main(String args[]) {

        System.out.println(someString());
        System.out.println("---AGAIN---");
        System.out.println(someString());
        System.out.println("---PRINT THE RESULT---");
        System.out.println(sb.toString());
    }

    private static String someString() {

        try {
            sb.append("-abc-");
            return sb.toString();

        } finally {
            sb.append("xyz");
        }
    }
}

Pada Java 1.8.162, blok kode di atas memberikan output berikut:

-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz

ini berarti bahwa menggunakan finallyuntuk membebaskan objek adalah praktik yang baik seperti kode berikut:

private static String someString() {

    StringBuilder sb = new StringBuilder();

    try {
        sb.append("abc");
        return sb.toString();

    } finally {
        sb = null; // Just an example, but you can close streams or DB connections this way.
    }
}
Sam
sumber
Bukankah seharusnya sb.setLength(0)pada akhirnya?
user7294900
sb.setLength (0) hanya akan mengosongkan data di StringBuffer. Jadi, sb = null akan memisahkan objek dari referensi.
Sam
Bukankah "xyz" harus dicetak dua kali pada output? Karena fungsi dipanggil dua kali, mengapa "akhirnya" hanya sekali?
fresko
2
Ini bukan praktik yang baik. Yang akhirnya diblokir dengan sb = null;hanya menambahkan kode yang tidak dibutuhkan. Saya mengerti maksud Anda bahwa finallyblok adalah tempat yang bagus untuk sumber daya gratis seperti koneksi database atau sesuatu seperti itu, tetapi perlu diingat bahwa contoh Anda dapat membingungkan pendatang baru.
Roc Boronat
1
@ Samim Terima kasih, saya menambahkan garis System.out.println("---AGAIN2---"); System.out.println(sb);dan sekarang lebih jelas. Karena itu, hasilnya bertentangan dengan tesis Anda: p Saya juga menambahkan jawaban Anda, tetapi hasil edit harus diterima oleh moderator atau orang seperti itu. Jika tidak, Anda dapat menambahkannya
fresko
7

Itu sebenarnya benar dalam bahasa apa pun ... akhirnya akan selalu dieksekusi sebelum pernyataan kembali, tidak peduli di mana pengembalian itu dalam tubuh metode. Jika bukan itu masalahnya, blok akhirnya tidak akan memiliki banyak arti.

Scott Dorman
sumber
7

Selain poin tentang pengembalian akhirnya menggantikan pengembalian di blok percobaan, hal yang sama berlaku untuk pengecualian. Blok akhirnya yang melempar pengecualian akan menggantikan pengembalian atau pengecualian yang dilemparkan dari dalam blok try.

Alex Miller
sumber
7

finally akan mengeksekusi dan itu sudah pasti.

finally tidak akan dieksekusi dalam kasus di bawah ini:

kasus 1 :

Ketika Anda mengeksekusi System.exit() .

kasus 2:

Saat JVM / Thread Anda mogok.

kasus 3:

Ketika eksekusi Anda dihentikan di antara secara manual.

Utkash Bhatt
sumber
6
  1. Akhirnya Block selalu dieksekusi. Kecuali dan sampai pernyataan System.exit () ada di sana (pernyataan pertama di blok akhirnya).
  2. Jika system.exit () adalah pernyataan pertama maka blok akhirnya tidak akan dieksekusi dan kontrol keluar dari blok akhirnya. Kapan saja pernyataan System.exit () masuk akhirnya memblokir sampai pernyataan itu akhirnya memblokir dieksekusi dan ketika System.exit () muncul, maka kontrol kekuatan sepenuhnya keluar dari blok akhirnya.
Avinash Pande
sumber
1
Ini telah dijawab berkali-kali, jadi informasi baru apa yang ditambahkan jawaban Anda?
Tom