Apakah penggunaan kata kunci akhir di Jawa meningkatkan kinerja?

347

Di Jawa kami melihat banyak tempat di mana finalkata kunci dapat digunakan tetapi penggunaannya tidak umum.

Sebagai contoh:

String str = "abc";
System.out.println(str);

Dalam kasus di atas, strbisa finaltetapi ini biasanya ditinggalkan.

Ketika suatu metode tidak akan ditimpa, kita dapat menggunakan kata kunci terakhir. Demikian pula dalam kasus kelas yang tidak akan diwarisi.

Apakah penggunaan kata kunci akhir dalam salah satu atau semua kasus ini benar-benar meningkatkan kinerja? Jika demikian, lalu bagaimana? Tolong jelaskan. Jika penggunaan yang tepat finalsangat penting untuk kinerja, kebiasaan apa yang harus dikembangkan oleh seorang programmer Java untuk memanfaatkan kata kunci dengan sebaik-baiknya?

Abhishek Jain
sumber
Saya tidak berpikir begitu sobat, metode pengiriman (caching situs panggilan dan ...) adalah masalah dalam bahasa dinamis bukan dalam bahasa jenis statis
Jahan
Jika saya menjalankan alat PMD saya (plugin untuk gerhana) yang digunakan untuk meninjau tujuan, itu menyarankan untuk membuat perubahan untuk variabel dalam kasus seperti yang ditunjukkan di atas. Tapi saya tidak mengerti konsepnya. Benarkah kinerjanya sangat menyentuh ??
Abhishek Jain
5
Saya pikir ini adalah pertanyaan ujian yang umum. Saya ingat bahwa final memang memiliki pengaruh terhadap kinerja, kelas final IIRC dapat dioptimalkan oleh JRE dalam beberapa cara karena mereka tidak dapat disubklasifikasikan.
Kawu
Saya sebenarnya sudah menguji ini. Pada semua JVM saya menguji penggunaan final pada variabel lokal apakah meningkatkan kinerja (sedikit, tetapi tetap bisa menjadi faktor dalam metode utilitas). Kode sumber ada dalam jawaban saya di bawah ini.
rustyx
1
"optimasi prematur adalah akar dari semua kejahatan". Biarkan saja kompiler melakukan tugasnya. Tulis kode komentar yang mudah dibaca dan baik. Itu selalu pilihan terbaik!
kaiser

Jawaban:

285

Biasanya tidak. Untuk metode virtual, HotSpot melacak apakah metode tersebut benar-benar telah ditimpa, dan mampu melakukan optimasi seperti menggarisbawahi asumsi bahwa metode belum ditimpa - sampai memuat kelas yang menimpa metode, pada titik mana itu dapat membatalkan (atau membatalkan sebagian) optimasi tersebut.

(Tentu saja, ini dengan asumsi Anda menggunakan HotSpot - tapi sejauh ini JVM yang paling umum, jadi ...)

Menurut saya, Anda harus menggunakan finalberdasarkan pada desain yang jelas dan mudah dibaca daripada untuk alasan kinerja. Jika Anda ingin mengubah apa pun karena alasan kinerja, Anda harus melakukan pengukuran yang sesuai sebelum membengkokkan kode yang paling jelas - sehingga Anda dapat memutuskan apakah kinerja tambahan yang dicapai sepadan dengan keterbacaan / desain yang lebih buruk. (Dalam pengalaman saya hampir tidak pernah sepadan; YMMV.)

EDIT: Seperti bidang terakhir telah disebutkan, ada baiknya mengangkat bahwa mereka sering merupakan ide yang baik, dalam hal desain yang jelas. Mereka juga mengubah perilaku yang dijamin dalam hal visibilitas cross-thread: setelah konstruktor selesai, setiap bidang terakhir dijamin akan terlihat di utas lainnya segera. Ini mungkin adalah penggunaan paling umum finaldalam pengalaman saya, meskipun sebagai pendukung Josh Bloch "desain untuk warisan atau melarangnya" aturan praktis, saya mungkin harus menggunakan finallebih sering untuk kelas ...

Jon Skeet
sumber
1
@Abhishek: Tentang apa khususnya? Poin yang paling penting adalah yang terakhir - bahwa Anda hampir pasti tidak perlu khawatir tentang ini.
Jon Skeet
9
@ Albishek: finalumumnya direkomendasikan karena membuat kode lebih mudah dipahami, dan membantu menemukan bug (karena itu membuat maksud programer eksplisit). PMD mungkin merekomendasikan untuk digunakan finalkarena masalah gaya ini, bukan karena alasan kinerja.
sleske
3
@Abhishek: Banyak yang cenderung spesifik JVM, dan mungkin bergantung pada aspek konteks yang sangat halus. Sebagai contoh, saya percaya server HotSpot JVM masih akan memungkinkan inlining metode virtual ketika ditimpa dalam satu kelas, dengan pemeriksaan tipe cepat jika perlu. Tetapi detailnya sulit dijabarkan dan mungkin berubah di antara yang dirilis.
Jon Skeet
5
Di sini saya akan mengutip Jawa Efektif, 2nd Edition, Butir 15, Minimalkan berubah-ubah: Immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.. Selanjutnya An immutable object can be in exactly one state, the state in which it was created.vs Mutable objects, on the other hand, can have arbitrarily complex state spaces.. Dari pengalaman pribadi saya, menggunakan kata kunci finalharus menyoroti niat pengembang untuk condong ke arah ketidakberdayaan, bukan untuk "mengoptimalkan" kode. Saya mendorong Anda untuk membaca bab ini, menarik!
Louis F.
2
Jawaban lain menunjukkan bahwa menggunakan finalkata kunci pada variabel dapat mengurangi jumlah bytecode, yang dapat menghasilkan efek pada kinerja.
Julien Kronegg
86

Jawaban singkat: jangan khawatir tentang itu!

Jawaban panjang:

Ketika berbicara tentang variabel lokal akhir, ingatlah bahwa menggunakan kata kunci finalakan membantu kompiler mengoptimalkan kode secara statis , yang pada akhirnya dapat menghasilkan kode yang lebih cepat. Sebagai contoh, String terakhir a + bdalam contoh di bawah ini digabungkan secara statis (pada waktu kompilasi).

public class FinalTest {

    public static final int N_ITERATIONS = 1000000;

    public static String testFinal() {
        final String a = "a";
        final String b = "b";
        return a + b;
    }

    public static String testNonFinal() {
        String a = "a";
        String b = "b";
        return a + b;
    }

    public static void main(String[] args) {
        long tStart, tElapsed;

        tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            testFinal();
        tElapsed = System.currentTimeMillis() - tStart;
        System.out.println("Method with finals took " + tElapsed + " ms");

        tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            testNonFinal();
        tElapsed = System.currentTimeMillis() - tStart;
        System.out.println("Method without finals took " + tElapsed + " ms");

    }

}

Hasil?

Method with finals took 5 ms
Method without finals took 273 ms

Diuji pada Java Hotspot VM 1.7.0_45-b18.

Jadi berapa peningkatan kinerja yang sebenarnya? Saya tidak berani mengatakannya. Dalam kebanyakan kasus mungkin marjinal (~ 270 nanodetik dalam tes sintetis ini karena rangkaian string dihindari sama sekali - kasus yang jarang terjadi), tetapi dalam kode utilitas yang sangat optimal mungkin menjadi faktor. Bagaimanapun jawaban untuk pertanyaan awal adalah ya, itu mungkin meningkatkan kinerja, tetapi sedikit di terbaik .

Selain manfaat kompilasi waktu, saya tidak dapat menemukan bukti bahwa penggunaan kata kunci finalmemiliki efek terukur terhadap kinerja.

rustyx
sumber
2
Saya menulis ulang kode Anda sedikit untuk menguji kedua kasus 100 kali. Akhirnya waktu rata-rata final adalah 0 ms dan 9 ms untuk non final. Meningkatkan hitungan iterasi ke 10M, atur rata-rata menjadi 0 ms dan 75 ms. Proses terbaik untuk non final adalah 0 ms. Mungkin VM mendeteksi hasil hanya dibuang begitu saja? Saya tidak tahu, tetapi terlepas dari itu, penggunaan final memang membuat perbedaan yang signifikan.
Casper Færgemand
5
Tes cacat. Tes yang lebih awal akan memanaskan JVM dan mendapatkan keuntungan dari pemanggilan tes nanti. Atur ulang tes Anda dan lihat apa yang terjadi. Anda perlu menjalankan setiap tes dalam instance JVM sendiri.
Steve Kuo
16
Tidak, tes tidak cacat, pemanasan diperhitungkan. Tes kedua adalah SLOWER, tidak lebih cepat. Tanpa pemanasan, tes kedua adalah BAHKAN PERLAHAN.
rustyx
6
Dalam testFinal () semua waktu mengembalikan objek yang sama, dari kumpulan string, karena pengecekan ulang string akhir dan string literal dievaluasi pada waktu kompilasi. testNonFinal () setiap kali mengembalikan objek baru, itu menjelaskan perbedaan dalam kecepatan.
anber
4
Apa yang membuat Anda berpikir skenario itu tidak realistis? Stringpenggabungan adalah operasi yang jauh lebih mahal daripada menambahkan Integers. Melakukannya secara statis (jika mungkin) lebih efisien, itulah yang ditunjukkan oleh tes ini.
rustyx
62

Ya itu bisa. Ini adalah contoh di mana final dapat meningkatkan kinerja:

Kompilasi bersyarat adalah teknik di mana baris kode tidak dikompilasi ke dalam file kelas berdasarkan kondisi tertentu. Ini dapat digunakan untuk menghapus banyak kode debug dalam build produksi.

pertimbangkan hal berikut:

public class ConditionalCompile {

  private final static boolean doSomething= false;

    if (doSomething) {
       // do first part. 
    }

    if (doSomething) {
     // do second part. 
    }

    if (doSomething) {     
      // do third part. 
    }

    if (doSomething) {
    // do finalization part. 
    }
}

Dengan mengubah atribut doSomething menjadi atribut final, Anda telah memberi tahu kompiler bahwa setiap kali ia melihat doSomething, ia harus menggantinya dengan false sesuai dengan aturan substitusi waktu kompilasi. Lulus pertama dari compiler mengubah kode untuk sesuatu seperti ini:

public class ConditionalCompile {

  private final static boolean doSomething= false;

    if (false){
       // do first part. 
    }

    if (false){
     // do second part. 
    }

    if (false){
      // do third part. 
    }

    if (false){
    // do finalization part. 

    }
}

Setelah ini selesai, kompiler akan memeriksanya lagi dan melihat bahwa ada pernyataan yang tidak terjangkau dalam kode. Karena Anda bekerja dengan kompiler berkualitas tinggi, itu tidak suka semua kode byte yang tidak dapat dijangkau. Jadi itu menghapus mereka, dan Anda berakhir dengan ini:

public class ConditionalCompile {


  private final static boolean doSomething= false;

  public static void someMethodBetter( ) {

    // do first part. 

    // do second part. 

    // do third part. 

    // do finalization part. 

  }
}

sehingga mengurangi kode yang berlebihan, atau pemeriksaan bersyarat yang tidak perlu.

Sunting: Sebagai contoh, mari kita ambil kode berikut:

public class Test {
    public static final void main(String[] args) {
        boolean x = false;
        if (x) {
            System.out.println("x");
        }
        final boolean y = false;
        if (y) {
            System.out.println("y");
        }
        if (false) {
            System.out.println("z");
        }
    }
}

Ketika mengkompilasi kode ini dengan Java 8 dan mendekompilasi dengan javap -c Test.classkita mendapatkan:

public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static final void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: ifeq          14
       6: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       9: ldc           #22                 // String x
      11: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      14: iconst_0
      15: istore_2
      16: return
}

Kita dapat mencatat bahwa kode yang dikompilasi hanya mencakup variabel non-final x. Ini membuktikan bahwa variabel akhir memiliki dampak pada kinerja, setidaknya untuk kasus sederhana ini.

mel3kings
sumber
1
@ ŁukaszLech Saya mempelajari ini dari buku Oreilly: Hardcore Java, pada bab mereka mengenai kata kunci terakhir.
mel3kings
15
Ini berbicara tentang pengoptimalan pada waktu kompilasi, berarti pengembang mengetahui NILAI variabel boolean akhir pada waktu kompilasi, apa gunanya seluruh titik penulisan jika blok di tempat pertama kemudian untuk skenario ini di mana JIKA-KONDISI tidak diperlukan dan tidak membuat masuk akal? Menurut pendapat saya, bahkan jika ini meningkatkan kinerja, ini adalah kode yang salah di tempat pertama dan dapat dioptimalkan oleh pengembang sendiri daripada menyerahkan tanggung jawab kepada kompiler dan pertanyaan utamanya bermaksud untuk bertanya tentang peningkatan kinerja dalam kode biasa di mana final digunakan yang masuk akal terprogram.
Bhavesh Agarwal
7
Intinya adalah menambahkan pernyataan debugging seperti yang dinyatakan oleh mel3kings. Anda bisa membalik variabel sebelum membangun produksi (atau mengkonfigurasinya dalam skrip pembuatan Anda) dan secara otomatis menghapus semua kode itu ketika distribusi dibuat.
Adam
16

Saya kagum bahwa tidak ada yang benar-benar memposting beberapa kode nyata yang tidak dikompilasi untuk membuktikan bahwa setidaknya ada beberapa perbedaan kecil.

Untuk referensi ini telah diuji terhadap javacversi 8, 9dan 10.

Misalkan metode ini:

public static int test() {
    /* final */ Object left = new Object();
    Object right = new Object();

    return left.hashCode() + right.hashCode();
}

Mengkompilasi kode ini sebagaimana adanya, menghasilkan kode byte yang sama persis seperti ketika finalakan ada ( final Object left = new Object();).

Tapi yang ini:

public static int test() {
    /* final */ int left = 11;
    int right = 12;
    return left + right;
}

Menghasilkan:

   0: bipush        11
   2: istore_0
   3: bipush        12
   5: istore_1
   6: iload_0
   7: iload_1
   8: iadd
   9: ireturn

Meninggalkan finaluntuk hadir menghasilkan:

   0: bipush        12
   2: istore_1
   3: bipush        11
   5: iload_1
   6: iadd
   7: ireturn

Kode ini cukup jelas, jika ada konstanta waktu kompilasi, kode itu akan dimuat langsung ke tumpukan operan (tidak akan disimpan ke dalam array variabel lokal seperti contoh sebelumnya melalui bipush 12; istore_0; iload_0) - yang agak masuk akal karena tidak ada yang bisa mengubahnya.

Di sisi lain mengapa dalam kasus kedua kompiler tidak menghasilkan di istore_0 ... iload_0luar saya, tidak seperti slot 0yang digunakan dengan cara apa pun (itu bisa menyusutkan variabel array dengan cara ini, tetapi mungkin saya kehilangan beberapa detail internal, tidak bisa katakan pasti)

Saya terkejut melihat optimasi seperti itu, mengingat betapa kecilnya yang javacdilakukan. Seharusnya kita selalu menggunakan final? Saya bahkan tidak akan menulis JMHtes (yang saya ingin awalnya), saya yakin bahwa diff adalah dalam urutan ns(jika memungkinkan untuk ditangkap sama sekali). Satu-satunya tempat ini bisa menjadi masalah, adalah ketika suatu metode tidak dapat digarisbawahi karena ukurannya (dan menyatakan finalakan mengecilkan ukuran itu dengan beberapa byte).

Ada dua lagi finalyang perlu ditangani. Pertama adalah ketika suatu metode final(dari JITperspektif), metode tersebut adalah monomorfik - dan ini adalah yang paling dicintai oleh JVM.

Lalu ada finalvariabel instan (yang harus ditetapkan di setiap konstruktor); ini penting karena mereka akan menjamin referensi yang dipublikasikan dengan benar, seperti disentuh sedikit di sini dan juga ditentukan secara tepat oleh JLS.

Eugene
sumber
Saya mengkompilasi kode menggunakan Java 8 (JDK 1.8.0_162) dengan opsi debug ( javac -g FinalTest.java), mendekompilasi kode menggunakan javap -c FinalTest.classdan tidak mendapatkan hasil yang sama (dengan final int left=12, saya dapatkan bipush 11; istore_0; bipush 12; istore_1; bipush 11; iload_1; iadd; ireturn). Jadi ya, bytecode yang dihasilkan bergantung pada banyak faktor dan sulit untuk mengatakan apakah memiliki finalatau tidak menghasilkan efek pada kinerja. Tetapi karena bytecode berbeda, beberapa perbedaan kinerja mungkin ada.
Julien Kronegg
13

Anda benar-benar bertanya tentang dua (setidaknya) kasus berbeda:

  1. final untuk variabel lokal
  2. final untuk metode / kelas

Jon Skeet sudah menjawab 2). Sekitar 1):

Saya tidak berpikir itu membuat perbedaan; untuk variabel lokal, kompilator dapat menyimpulkan apakah variabelnya final atau tidak (hanya dengan memeriksa apakah variabel tersebut ditugaskan lebih dari satu kali). Jadi jika kompiler ingin mengoptimalkan variabel yang hanya ditugaskan satu kali, ia dapat melakukannya tidak peduli apakah variabel tersebut benar-benar dinyatakan finalatau tidak.

final mungkin membuat perbedaan untuk bidang kelas yang dilindungi / publik; di sana sangat sulit bagi kompiler untuk mencari tahu apakah field sedang diset lebih dari sekali, karena bisa terjadi dari kelas yang berbeda (yang bahkan mungkin tidak dimuat). Tetapi meskipun demikian JVM dapat menggunakan teknik yang dijelaskan Jon (optimalkan secara optimis, kembalikan jika kelas dimuat yang mengubah bidang).

Singkatnya, saya tidak melihat alasan mengapa itu harus membantu kinerja. Jadi optimasi mikro semacam ini tidak mungkin membantu. Anda dapat mencoba membandingkannya untuk memastikan, tetapi saya ragu itu akan membuat perbedaan.

Edit:

Sebenarnya, menurut jawaban Timo Westkämper, final dapat meningkatkan kinerja untuk bidang kelas dalam beberapa kasus. Saya berdiri dikoreksi.

sleske
sumber
Saya tidak berpikir kompiler dapat dengan benar memeriksa berapa kali variabel lokal ditugaskan: bagaimana dengan if-then-else struct dengan banyak tugas?
gyorgyabraham
1
@gyabraham: Kompilator sudah memeriksa kasus ini jika Anda mendeklarasikan variabel lokal sebagai final, untuk memastikan Anda tidak menetapkannya dua kali. Sejauh yang saya bisa lihat, logika pemeriksaan yang sama dapat (dan mungkin) digunakan untuk memeriksa apakah suatu variabel bisa final.
sleske
Final variabel lokal tidak diekspresikan dalam bytecode, sehingga JVM bahkan tidak tahu itu final
Steve Kuo
1
@SteveKuo: Sekalipun tidak diekspresikan dalam bytecode, mungkin membantu javacuntuk mengoptimalkan dengan lebih baik. Tapi ini hanya spekulasi.
sleske
1
Kompilator dapat mengetahui apakah variabel lokal telah ditetapkan tepat sekali, tetapi dalam praktiknya tidak (melampaui pengecekan kesalahan). Di sisi lain, jika suatu finalvariabel adalah tipe primitif atau tipe Stringdan segera ditugaskan dengan konstanta waktu kompilasi seperti pada contoh pertanyaan, kompiler harus memasukkannya, karena variabelnya adalah konstanta waktu kompilasi per spesifikasi. Tetapi untuk sebagian besar kasus penggunaan, kode mungkin terlihat berbeda, tetapi masih tidak ada bedanya apakah konstanta digariskan atau dibaca dari variabel kinerja lokal-bijaksana.
Holger
6

Catatan: Bukan ahli java

Jika saya ingat java saya dengan benar, akan ada sedikit cara untuk meningkatkan kinerja menggunakan kata kunci terakhir. Saya selalu tahu ada untuk "kode yang baik" - desain dan keterbacaan.

Neowizard
sumber
1

Saya bukan ahli, tetapi saya kira Anda harus menambahkan finalkata kunci ke kelas atau metode jika tidak akan ditimpa dan biarkan variabel sendirian. Jika ada cara untuk mengoptimalkan hal-hal seperti itu kompiler akan melakukannya untuk Anda.

Crozin
sumber
1

Sebenarnya, saat menguji beberapa kode terkait OpenGL, saya menemukan bahwa menggunakan pengubah akhir pada bidang pribadi dapat menurunkan kinerja. Inilah awal dari kelas yang saya uji:

public class ShaderInput {

    private /* final */ float[] input;
    private /* final */ int[] strides;


    public ShaderInput()
    {
        this.input = new float[10];
        this.strides = new int[] { 0, 4, 8 };
    }


    public ShaderInput x(int stride, float val)
    {
        input[strides[stride] + 0] = val;
        return this;
    }

    // more stuff ...

Dan ini adalah metode yang saya gunakan untuk menguji kinerja berbagai alternatif, di antaranya kelas ShaderInput:

public static void test4()
{
    int arraySize = 10;
    float[] fb = new float[arraySize];
    for (int i = 0; i < arraySize; i++) {
        fb[i] = random.nextFloat();
    }
    int times = 1000000000;
    for (int i = 0; i < 10; ++i) {
        floatVectorTest(times, fb);
        arrayCopyTest(times, fb);
        shaderInputTest(times, fb);
        directFloatArrayTest(times, fb);
        System.out.println();
        System.gc();
    }
}

Setelah iterasi ke-3, dengan pemanasan VM, saya secara konsisten mendapatkan angka-angka ini tanpa kata kunci terakhir:

Simple array copy took   : 02.64
System.arrayCopy took    : 03.20
ShaderInput took         : 00.77
Unsafe float array took  : 05.47

Dengan kata kunci terakhir:

Simple array copy took   : 02.66
System.arrayCopy took    : 03.20
ShaderInput took         : 02.59
Unsafe float array took  : 06.24

Perhatikan angka-angka untuk tes ShaderInput.

Tidak masalah apakah saya menjadikan ladang itu publik atau pribadi.

Kebetulan, ada beberapa hal lagi yang membingungkan. Kelas ShaderInput mengungguli semua varian lainnya, bahkan dengan kata kunci terakhir. Ini luar biasa b / c pada dasarnya adalah kelas pembungkus array float, sedangkan tes lainnya memanipulasi array secara langsung . Harus memikirkan ini. Mungkin ada hubungannya dengan antarmuka ShaderInput yang lancar.

System.arrayCopy juga sebenarnya agak lebih lambat untuk array kecil daripada hanya menyalin elemen dari satu array ke array lainnya dalam for. Dan menggunakan sun.misc.Unsafe (dan juga java.nio.FloatBuffer langsung, tidak ditampilkan di sini) berkinerja buruk.

pengguna3663845
sumber
1
Anda lupa membuat parameter menjadi final. <pre> <code> ShaderInput publik x (langkah int terakhir, final float val) {input [langkah [langkah] + 0] = val; kembalikan ini; } </code> </pre> Dalam pengalaman saya, melakukan variabel atau final bidang apa saja memang dapat meningkatkan kinerja.
Anticro
1
Oh, dan jadikan yang lainnya juga final: <pre> <code> final int arraySize = 10; float akhir [] fb = float baru [arraySize]; untuk (int i = 0; i <arraySize; i ++) {fb [i] = random.nextFloat (); } waktu int akhir = 1000000000; untuk (int i = 0; i <10; ++ i) {floatVectorTest (times, fb); arrayCopyTest (times, fb); shaderInputTest (times, fb); directFloatArrayTest (times, fb); System.out.println (); System.gc (); } </code> </pre>
Anticro
1

Final (Setidaknya untuk variabel dan parameter anggota) lebih untuk manusia daripada untuk mesin.

Ini praktik yang baik untuk membuat variabel menjadi final sedapat mungkin. Saya berharap Java telah membuat "variabel" final secara default dan memiliki kata kunci "Mutable" untuk memungkinkan perubahan. Kelas yang tidak dapat diubah mengarah ke kode ulir yang lebih baik, dan hanya dengan melirik kelas dengan "akhir" di depan setiap anggota akan dengan cepat menunjukkannya sebagai tidak dapat diubah.

Kasus lain - Saya telah mengonversi banyak kode untuk menggunakan @ NonNull / @ Nullable annotations (Anda dapat mengatakan parameter metode tidak boleh nol maka IDE dapat memperingatkan Anda setiap tempat Anda melewati variabel yang tidak ditandai @) NonNull - semuanya menyebar ke tingkat yang konyol). Jauh lebih mudah untuk membuktikan variabel anggota atau parameter tidak boleh nol ketika ditandai final karena Anda tahu itu tidak ditugaskan kembali di tempat lain.

Saran saya adalah membiasakan menerapkan final untuk anggota dan parameter secara default, Ini hanya beberapa karakter tetapi akan mendorong Anda ke arah meningkatkan gaya pengkodean Anda jika tidak ada yang lain.

Final untuk metode atau kelas adalah konsep lain karena ini melarang bentuk penggunaan kembali yang sangat valid dan tidak terlalu banyak memberi tahu pembaca. Penggunaan terbaik mungkin adalah cara mereka membuat String dan tipe intrinsik lainnya menjadi final sehingga Anda dapat mengandalkan perilaku konsisten di mana-mana - Itu mencegah banyak bug (walaupun ada kalanya saya akan MENYUKAI untuk memperpanjang string .... oh the kemungkinan)

Bill K.
sumber
0

Seperti disebutkan di tempat lain, 'final' untuk variabel lokal, dan pada tingkat yang sedikit lebih rendah dari variabel anggota, lebih merupakan masalah gaya.

'final' adalah pernyataan bahwa Anda bermaksud variabel untuk tidak berubah (yaitu, variabel tidak akan bervariasi!). Kompiler kemudian dapat membantu Anda keluar dengan mengeluh jika Anda melanggar kendala Anda sendiri.

Saya berbagi sentimen bahwa Java akan menjadi bahasa yang lebih baik jika pengidentifikasi (Maaf, saya tidak bisa menyebut hal yang tidak bervariasi sebagai 'variabel') adalah final secara default, dan mengharuskan Anda untuk secara eksplisit mengatakan bahwa mereka adalah variabel. Tetapi setelah mengatakan itu, saya biasanya tidak menggunakan 'final' pada variabel lokal yang diinisialisasi dan tidak pernah ditugaskan; sepertinya terlalu berisik.

(Saya menggunakan final pada variabel anggota)

pengguna13752845
sumber
-3

Anggota menyatakan dengan final akan tersedia di seluruh program karena tidak seperti yang nonfinal, jika anggota ini belum digunakan dalam program, tetap saja mereka tidak akan dirawat oleh Pengumpul Sampah sehingga dapat menyebabkan masalah kinerja karena manajemen memori yang buruk.

nams
sumber
2
Omong kosong macam apa ini? Apakah Anda punya sumber mengapa Anda berpikir demikian?
J. Doe
-4

final kata kunci dapat digunakan dalam lima cara di Jawa.

  1. Kelas adalah final
  2. Variabel referensi adalah final
  3. Variabel lokal adalah final
  4. Suatu metode bersifat final

Kelas adalah final: kelas adalah final berarti kita tidak dapat diperpanjang atau warisan berarti warisan tidak mungkin.

Demikian pula - Objek adalah final: beberapa waktu kita tidak mengubah keadaan internal objek sehingga dalam kasus seperti itu kita dapat menentukan objek adalah objek akhir. Tujuan akhir berarti bukan variabel juga final.

Setelah variabel referensi dibuat final, itu tidak dapat dipindahkan ke objek lain. Tapi bisa mengubah konten objek selama bidangnya belum final

adityaraj
sumber
2
Dengan "objek adalah final" maksudmu "objek tidak berubah".
gyorgyabraham
6
Anda benar, tetapi Anda tidak menjawab pertanyaan itu. OP tidak bertanya apa finalartinya, tetapi apakah menggunakan finalmempengaruhi kinerja.
Honza Zidek