Java yöntemi argümanlarını nihai olarak oluşturma


92

finalAşağıdaki kod arasında ne fark yaratır? Argümanları olarak bildirmenin herhangi bir avantajı var mı final?

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

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

4
Bir parametrenin yeniden kullanılması veya yeniden atanması durumunda uyarı veren kod çözümleyicileri vardır. (Yerel değişkenler için aynıdır) IMHO, Bu tür parametreleri değiştirmenin istenmediğini düşünürseniz bu daha iyi bir yoldur.
Peter Lawrey


Java'nın tüm girdi yöntemi argümanlarını varsayılan olarak nihai hale getirmesi gerektiğini düşünüyorum. Ve sonra referansı değiştirmek istersem, bunu manuel olarak yapmam gerekir. Bu şekilde, suçluluk faktörü bu tür birçok davayı önleyecektir.
Sid

Yanıtlar:


131

Biçimsel bir yöntem parametresi yerel bir değişken olduğundan, bunlara yalnızca son olarak bildirildikleri takdirde iç anonim sınıflardan erişebilirsiniz.

Bu sizi yöntem gövdesinde başka bir yerel son değişken bildirmekten kurtarır:

 void m(final int param) {
        new Thread(new Runnable() {
            public void run() {
                System.err.println(param);
            }
        }).start();
    }

27
+1: Bu önemli bir kullanım durumudur ve ihtiyacınız olduğu tek zamandır . (Geri kalan zamanlarda, programcıya yardım etmek için neyin uygun olduğu meselesi.)
Donal Fellows

3
Bunun arkasındaki sebebi sorabilir miyim?
KodeWarrior

21
Java 8 ile
artık

3
@simgineer burayı okuyun: stackoverflow.com/questions/28408109/…
PeterMmm

3
@AmitParashar Doğru, ancak Java 8, değişkeni bir iç sınıfta her kullanmanız gerektiğinde sizi "final" anahtar kelimesini kullanmak zorunda kalmaktan kurtarıyor ... Gerçek şu ki, derleyici yalnızca sonluluğu örtük yapıyor, siz hala değişkenin etkili bir şekilde son olması gerekir ... Yani, daha sonra ona atamaya çalışmanız durumunda yine de bir derleme zamanı hatası alırsınız! Java 8 : SNEAK 100 :)
varun

38

Ayıkla final anahtar üzerinde son kelime

Nihai Parametreler

Aşağıdaki örnek, nihai parametreleri bildirir:

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, i ve j dizinlerinin yanlışlıkla yöntem tarafından sıfırlanmamasını sağlamak için burada kullanılır. Parametrelerinizin değerini yanlışlıkla değiştiren sinsi bir hataya karşı korumanın kullanışlı bir yoludur. Genel olarak konuşursak, kısa yöntemler bu hata sınıfından korunmanın daha iyi bir yoludur, ancak son parametreler kodlama stilinize faydalı bir katkı olabilir.

Son parametrelerin yöntem imzasının bir parçası olarak kabul edilmediğini ve yöntem çağrılarını çözerken derleyici tarafından göz ardı edildiğini unutmayın. Parametreler, yöntemin nasıl geçersiz kılınacağı üzerinde hiçbir etkisi olmaksızın nihai (veya değil) olarak ilan edilebilir.


18
İlkel değişiklikler her zaman yalnızca yöntemin içinde görülebileceğinden, bu örnekte ilkel öğeler yerine nesneleri kullanmak daha iyi olabilir. Ve nesneler söz konusu olduğunda, onları yine de değiştirebilirsiniz. Yeni bir nesneyi işaret edemezsiniz. Aslında şimdi düşünüyorum, final, AIC'lerle değişken bir bildirimi kaydetmek ve derleyicinin herhangi bir nedenle değiştirmek istemediğiniz parametrelerin yanlışlıkla değiştirilmesini göstermesi dışında, onu dışarıda bırakmaya kıyasla gerçekten hiçbir şeyi değiştirmiyor. .
Rob Grant

27

Son, değişkene yeni bir değer atamanızı engeller ve bu, yazım hatalarını yakalamada yardımcı olabilir. Biçimsel olarak, alınan parametreleri değiştirmeden tutmak ve yalnızca yerel değişkenlere atamak isteyebilirsiniz, bu nedenle final, bu stilin uygulanmasına yardımcı olacaktır.

İtiraf etmeliyim ki parametreler için final kullanmayı nadiren hatırlıyorum, belki de yapmalıyım.

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;
}

1
Argümanları nihai olarak ilan etmenin nasıl yararlı olabileceğine dair harika bir örnek. Ben buna kısmi değilim ama aynı zamanda 3+ parametre için ağız dolusu.
JoseHdez_2

14

Çok fazla fark yaratmaz. Bu sadece yazamayacağın anlamına gelir:

stamp = null;
fTz = new ...;

ama yine de yazabilirsin:

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

Temelde bakım programcısına, yönteminizin ortasındaki bir yerde parametreye yeni bir değer atamayacağınız ve bu nedenle kafa karışıklığına neden olabileceği konusunda bir ipucu.


3

Java'da parametreler / değişkenler için kullanıldığında son anahtar kelime referansı son olarak işaretler. Bir nesnenin başka bir yönteme geçirilmesi durumunda, sistem referans değişkeninin bir kopyasını oluşturur ve onu yönteme iletir. Yeni referansları nihai olarak işaretleyerek onları yeniden atanmaya karşı korursunuz. Bazen iyi bir kodlama uygulaması olarak kabul edilir.


1
Bir şey eklemem gerekiyor: eğer parametreler ilkelse, herhangi bir farklılık görmüyorum. Ayrıca, parametreler Koleksiyonlar ise (nesnelerin listesi ...), final eklemek değiştirilmelerini engelleyemezdi.
Sam003

1
Değişmezlik her zaman arzu edilen bir özelliktir. Java bunu kutudan çıkarmaz. Değişkenleri nihai hale getirmek en azından referans bütünlüğünü sağlar.
Sid

1
Katılıyorum. Ancak nesneler için gerçekten değişmezlik elde etmek istiyorsak, derin bir klon yapmayı deneyebiliriz.
Sam003

2

Bu yöntemin gövdesi için finalanahtar kelime, argüman referanslarının yanlışlıkla yeniden atanmasını önleyerek bu durumlarda bir derleme hatası verir (çoğu IDE hemen şikayet eder). Bazıları, finalmümkün olduğunda genel olarak kullanmanın işleri hızlandıracağını iddia edebilir, ancak son JVM'lerde durum böyle değil.


2

Gördüğüm iki avantaj listeleniyor:

1 Yöntem bağımsız değişkeninin son olarak işaretlenmesi, yöntemin içindeki bağımsız değişkenin yeniden atanmasını önler

Senden örnek

    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 ..
    
    }

Karmaşık bir yöntemde, bağımsız değişkenleri son olarak işaretlemek, bu bağımsız değişkenlerin yerel değişkenler olarak yanlışlıkla yorumlanmasına yardımcı olacaktır ve derleyici olarak yeniden atamak, bu durumları örnekte gösterildiği gibi işaretleyecektir.

2 Argümanı anonim bir iç sınıfa geçirmek

Biçimsel bir yöntem parametresi yerel bir değişken olduğundan, bunlara yalnızca son olarak bildirildikleri takdirde iç anonim sınıflardan erişebilirsiniz.


1

- Geçmişte (Java 8'den önce :-))

"Final" anahtar kelimesinin açıkça kullanılması, dahili anonim sınıflar için yöntem değişkeninin erişilebilirliğini etkiledi.

- Modern (Java 8+) dilinde böyle bir kullanıma gerek yoktur:

Java, "etkili bir şekilde son" değişkenleri tanıttı. Kod değişkenin değerinin değiştirilmesini gerektirmiyorsa, yerel değişkenler ve yöntem parametrelerinin nihai olduğu varsayılır. Yani Java8 + 'da böyle bir anahtar kelime görürseniz, bunun gereksiz olduğunu varsayabilirsiniz. "Etkili son" un tanıtımı, lambdaları kullanırken daha az kod yazmamızı sağlar.


0

Bu sadece bir sözleşme tanımlamanıza ve ona bağlı kalmanıza yardımcı olacak bir Java yapısıdır. Burada benzer bir tartışma: http://c2.com/cgi/wiki?JavaFinalConsacefulEvil

BTW - (twiki'nin dediği gibi), eğer iyi programlama ilkelerini takip ediyorsanız ve gelen argüman referansını yeniden atamayı / yeniden tanımlamayı bitirdiyseniz, argümanları son olarak işaretlemek genellikle gereksizdir.

En kötü durumda, args referansını yeniden tanımlarsanız, işleve aktarılan gerçek değeri etkilemeyecektir - çünkü yalnızca bir referans aktarılmıştır.


0

Genel olarak değişkenleri ve alanları son olarak işaretlemekten bahsediyorum - sadece yöntem argümanlarına uygulanmaz. (Yöntemleri / sınıfları final olarak işaretlemek tamamen farklı bir şeydir).

Bu, kodunuzun okuyucularına / gelecekteki geliştiricilerine bir iyiliktir. Değişkenin mantıklı bir adıyla birlikte, söz konusu değişkenlerin neyi temsil ettiğini görmek / anlamak kodunuzun okuyucusuna yardımcı ve güven vericidir - ve değişkeni aynı kapsamda gördüğünüzde, anlamın aynı kaldığı okuyucuya güven verir. aynı şekilde, her bağlamda bir değişkenin ne anlama geldiğini her zaman anlamak için kafasını kaşıyması gerekmez. Değişkenlerin "yeniden kullanımının" çok fazla kötüye kullanıldığını gördük, bu da kısa bir kod parçacığını anlamayı zorlaştırıyor.


-3

Son anahtar kelime, parametreye yeni bir değer atamanızı engeller. Bunu basit bir örnekle açıklamak istiyorum

Bir yöntemimiz olduğunu varsayalım

Yöntem 1(){

Date dateOfBirth = new Date ("1/1/2009");

method2 (dateOfBirth);

method3 (dateOfBirth); }

genel mehod2 (Doğum tarihi) {
....
....
....
}

genel mehod2 (Doğum tarihi) {
....
....
....
}

Yukarıdaki durumda, "dateOfBirth" yöntem 2'de yeni bir değer atanırsa, bu, yöntem3'ten yanlış çıktıya neden olur. Method3'e iletilen değer, method2'ye geçirilmeden önceki değer olmadığı için. Bu nedenle, bu son anahtar kelimeden kaçınmak için parametreler için kullanılır.

Ve bu aynı zamanda Java Kodlama En İyi Uygulamalarından biridir.


5
Bu pek doğru değil. DateOfBirth bağımsız değişkeni method2 () 'deki başka bir değere değiştirilse bile, Java referansla değil değere göre geçtiğinden, method2 () üzerinde hiçbir etkisi olmayacaktır.
Flo
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.