Membuat argumen metode java sebagai final

92

Apa perbedaan yang finalmembuat antara kode di bawah ini. Apakah ada keuntungan dalam mendeklarasikan argumen sebagai final.

public String changeTimezone( Timestamp stamp, Timezone fTz, Timezone toTz){  
    return ....
}

public String changeTimezone(final Timestamp stamp, final Timezone fTz, 
        final Timezone toTz){
    return ....
}
John
sumber
4
Ada penganalisis kode yang memperingatkan jika parameter digunakan kembali atau ditetapkan ulang. (Sama untuk variabel lokal) IMHO, Ini adalah cara yang lebih baik untuk menangkap parameter seperti itu jika Anda merasa mengubahnya tidak diinginkan.
Peter Lawrey
Saya merasa Java harus menjadikan semua argumen metode input sebagai final secara default. Dan kemudian jika saya ingin mengubah referensi, saya harus melakukannya secara manual. Dengan begitu, faktor rasa bersalah akan mencegah banyak kasus seperti itu.
Sid

Jawaban:

131

Karena parameter metode formal adalah variabel lokal, Anda dapat mengaksesnya dari kelas anonim dalam hanya jika dideklarasikan sebagai final.

Ini menyelamatkan Anda dari mendeklarasikan variabel final lokal lain di badan metode:

 void m(final int param) {
        new Thread(new Runnable() {
            public void run() {
                System.err.println(param);
            }
        }).start();
    }
PeterMmm
sumber
27
+1: Ini adalah kasus penggunaan yang penting, dan satu-satunya saat Anda membutuhkannya . (Sisa waktu itu hanya masalah apa yang nyaman untuk membantu programmer.)
Donal Fellows
3
Bolehkah saya menanyakan alasan di balik ini?
KodeWarrior
21
Tidak perlu lagi dengan Java 8.
Amit Parashar
3
@simgineer baca di sini: stackoverflow.com/questions/28408109/…
PeterMmm
3
@AmitParashar Benar, tetapi Java 8 hanya menyelamatkan Anda dari keharusan menggunakan kata kunci "final" setiap kali Anda harus menggunakan variabel di kelas dalam ... Kenyataannya adalah bahwa kompilator hanya membuat finalitas tersirat, Anda masih memerlukan variabel agar final secara efektif ... Jadi, Anda masih mendapatkan kesalahan waktu kompilasi jika Anda mencoba menetapkannya nanti! Jawa 8 : SNEAK 100 :)
varun
38

Ekstrak dari Kata terakhir pada kata kunci terakhir

Parameter Akhir

Contoh berikut mendeklarasikan parameter akhir:

public void doSomething(final int i, final int j)
{
  // cannot change the value of i or j here...
  // any change would be visible only inside the method...
}

final digunakan di sini untuk memastikan kedua indeks i dan j tidak akan diatur ulang secara tidak sengaja oleh metode ini. Ini adalah cara praktis untuk melindungi dari bug berbahaya yang secara keliru mengubah nilai parameter Anda. Secara umum, metode singkat adalah cara yang lebih baik untuk melindungi dari kelas kesalahan ini, tetapi parameter terakhir dapat menjadi tambahan yang berguna untuk gaya pengkodean Anda.

Perhatikan bahwa parameter akhir tidak dianggap sebagai bagian dari tanda tangan metode, dan diabaikan oleh compiler saat menyelesaikan panggilan metode. Parameter dapat dinyatakan final (atau tidak) tanpa memengaruhi cara penggantian metode.

pgras
sumber
18
Mungkin lebih baik menggunakan objek daripada primitif untuk contoh ini, karena perubahan primitif hanya akan selalu terlihat di dalam metode. Dan dalam kasus objek, Anda masih bisa mengubahnya. Anda tidak bisa menunjuk pada objek baru. Sebenarnya sekarang saya memikirkannya, final tidak benar-benar mengubah apa pun dibandingkan dengan membiarkannya, selain menyimpan deklarasi variabel dengan AIC dan meminta kompiler menunjukkan modifikasi parameter yang tidak disengaja yang tidak ingin Anda ubah karena alasan tertentu .
Rob Grant
27

Yang terakhir mencegah Anda memberikan nilai baru ke variabel, dan ini dapat membantu dalam menangkap kesalahan ketik. Secara gaya Anda mungkin ingin menjaga parameter yang diterima tidak berubah dan hanya menetapkan ke variabel lokal, jadi final akan membantu untuk menegakkan gaya itu.

Harus saya akui saya jarang ingat untuk menggunakan final untuk parameter, mungkin saya harus.

public int example(final int basicRate){
    int discountRate;

    discountRate = basicRate - 10;
    // ... lots of code here 
    if ( isGoldCustomer ) {
        basicRate--;  // typo, we intended to say discountRate--, final catches this
    }
    // ... more code here

    return discountRate;
}
djna
sumber
1
Contoh bagus tentang bagaimana mendeklarasikan argumen sebagai final dapat bermanfaat. Saya parsial untuk ini tetapi mereka juga seteguk untuk 3+ parameter.
JoseHdez_2
14

Itu tidak membuat banyak perbedaan. Itu hanya berarti Anda tidak dapat menulis:

stamp = null;
fTz = new ...;

tetapi Anda masih bisa menulis:

stamp.setXXX(...);
fTz.setXXX(...);

Ini terutama merupakan petunjuk bagi programmer pemeliharaan yang mengikuti Anda bahwa Anda tidak akan memberikan nilai baru ke parameter di suatu tempat di tengah metode Anda di mana tidak jelas dan karena itu dapat menyebabkan kebingungan.

Adrian Pronk
sumber
3

Kata kunci terakhir saat digunakan untuk parameter / variabel di Java menandai referensi sebagai final. Jika mengirimkan objek ke metode lain, sistem membuat salinan variabel referensi dan meneruskannya ke metode. Dengan menandai referensi baru sebagai final, Anda melindunginya dari penugasan ulang. Terkadang ini dianggap sebagai praktik pengkodean yang baik.

Sid
sumber
1
Saya harus menambahkan sesuatu: jika parameternya primitif, saya tidak melihat perbedaan apa pun. Selain itu, jika parameternya adalah Koleksi (daftar objek ...), menambahkan final tidak dapat mencegahnya untuk dimodifikasi.
Sam003
1
Kekekalan selalu merupakan sifat yang diinginkan. Java tidak memilikinya di luar kotak. Membuat variabel final setidaknya memastikan integritas referensi.
Sid
1
Saya setuju. Tetapi jika kita benar-benar ingin mencapai kekekalan untuk objek, kita bisa mencoba membuat klon yang dalam.
Sam003
2

Untuk tubuh metode ini, finalkata kunci akan mencegah referensi argumen tidak sengaja dipindahkan sehingga memberikan kesalahan kompilasi pada kasus tersebut (sebagian besar IDE akan langsung mengeluh). Beberapa orang mungkin berpendapat bahwa menggunakan finalsecara umum jika memungkinkan akan mempercepat, tetapi itu tidak terjadi di JVM baru-baru ini.

dimitrisli
sumber
2

Dua keuntungan yang saya lihat tercantum:

1 Menandai argumen metode sebagai final mencegah penugasan ulang argumen di dalam metode

Dari contoh Anda

    public String changeTimezone(final Timestamp stamp, final Timezone fTz, 
            final Timezone toTz){
    
    // THIS WILL CAUSE COMPILATION ERROR as fTz is marked as final argument

      fTz = Calendar.getInstance().getTimeZone();     
      return ..
    
    }

Dalam metode yang rumit, menandai argumen sebagai final akan membantu dalam interpretasi yang tidak disengaja dari argumen ini sebagai metode variabel lokal dan penugasan ulang sebagai kompilator akan menandai kasus ini seperti yang ditunjukkan dalam contoh.

2 Meneruskan argumen ke kelas dalam anonim

Karena parameter metode formal adalah variabel lokal, Anda dapat mengaksesnya dari kelas anonim dalam hanya jika dideklarasikan sebagai final.

Santhosh Urumese
sumber
1

- Dulu (sebelum Java 8 :-))

Jelaskan penggunaan kata kunci "akhir" yang memengaruhi aksesibilitas variabel metode untuk kelas anonim internal.

- Dalam bahasa modern (Java 8+) tidak diperlukan penggunaan seperti itu:

Java memperkenalkan variabel "efektif akhir". Variabel lokal dan parameter metode dianggap final jika kode tidak menyiratkan perubahan nilai variabel. Jadi jika Anda melihat kata kunci seperti itu di Java8 +, Anda dapat menganggapnya tidak perlu. Pengenalan "efektif akhir" membuat kita mengetik lebih sedikit kode saat menggunakan lambda.

Witold Kaczurba
sumber
0

Ini hanya sebuah konstruksi di Java untuk membantu Anda menentukan kontrak dan menaatinya. Diskusi serupa di sini: http://c2.com/cgi/wiki?JavaFinalConsideredEvil

BTW - (seperti yang dikatakan twiki), menandai args sebagai final umumnya berlebihan jika Anda mengikuti prinsip-prinsip pemrograman yang baik dan telah selesai menetapkan ulang / mendefinisikan ulang referensi argumen yang masuk.

Dalam kasus terburuk, jika Anda mendefinisikan ulang referensi args, ini tidak akan memengaruhi nilai sebenarnya yang diteruskan ke fungsi - karena hanya referensi yang diteruskan.

madhurtanwani
sumber
0

Saya berbicara tentang menandai variabel dan bidang akhir secara umum - tidak hanya berlaku untuk argumen metode. (Menandai metode / kelas akhir adalah hal yang sama sekali berbeda).

Ini membantu pembaca / pengelola masa depan kode Anda. Bersama dengan nama variabel yang masuk akal, sangat membantu dan meyakinkan pembaca kode Anda untuk melihat / memahami apa yang diwakili oleh variabel yang dimaksud - dan meyakinkan pembaca bahwa setiap kali Anda melihat variabel dalam ruang lingkup yang sama, artinya tetap ada. sama, jadi dia tidak perlu menggaruk-garuk kepalanya untuk selalu mencari tahu arti variabel dalam setiap konteks. Kami telah melihat terlalu banyak penyalahgunaan variabel "penggunaan kembali", yang bahkan membuat cuplikan kode pendek sulit untuk dipahami.

SINAR
sumber
-3

Kata kunci terakhir mencegah Anda menetapkan nilai baru ke parameter. Saya ingin menjelaskan ini dengan contoh sederhana

Misalkan kita punya metode

metode1 () {

Date dateOfBirth = Tanggal baru ("1/1/2009");

metode2 (dateOfBirth);

metode3 (dateOfBirth); }

publik mehod2 (Date dateOfBirth) {
....
....
....
}

publik mehod2 (Date dateOfBirth) {
....
....
....
}

Dalam kasus di atas, jika "dateOfBirth" diberi nilai baru di method2 maka ini akan menghasilkan keluaran yang salah dari method3. Karena nilai yang diteruskan ke method3 tidak seperti sebelum diteruskan ke method2. Jadi untuk menghindari kata kunci terakhir ini digunakan untuk parameter.

Dan ini juga salah satu Praktik Terbaik Pengkodean Java.

Kamal
sumber
5
Itu kurang tepat. Meskipun argumen dateOfBirth diubah ke nilai lain di method2 (), ini tidak akan berpengaruh pada method2 (), karena Java meneruskan nilai dan bukan dengan referensi.
Flo