Java'da, mecbur olmasam bile parametreler ve yerliler için “final” kullanmalı mıyım?


105

Java, değişkenlerin (alanlar / yerliler / parametreler) finalyeniden atanmasını önlemek için olarak işaretlenmesine izin verir . Bazı özelliklerin (veya tüm bir sınıfın) değişmez olması gerekip gerekmediğini hızlıca görmeme yardımcı olduğu için alanları çok faydalı buluyorum.

Öte yandan, yerliler ve parametrelerle daha az faydalı buluyorum ve genellikle onları finalasla tekrar atanmayacaklarmış gibi işaretlemekten kaçınıyorum (iç sınıfta kullanılması gerektiğinde açık bir istisna dışında) . Ancak, son zamanlarda, mümkün olduğunda son kullanılan kodu kullandım, teknik olarak daha fazla bilgi veriyordum.

Programlama tarzım hakkında artık kendime güvenmiyorum, bir finalyere başvurmanın başka avantajları ve dezavantajları nelerdir, en yaygın endüstri tarzı nedir ve neden?


@Amir kodlama tarzı sorular burada SO'dan daha iyi görünüyorlar ve SSS’de veya bu sitenin bununla ilgili metaında herhangi bir politika bulamadım. Lütfen beni yönlendirir misiniz?
Oak

1
@Oak Yazıyor: "Özel programlama problemi, yazılım algoritmaları, kodlama , Yığın Taşması isteyin"
Amir Rezaei

7
@Amir katılmıyorum, bunun bir kodlama problemi olduğunu anlamıyorum. Her durumda bu tartışma buraya ait değil, bu yüzden bu konuda bir meta-konu açtım .
Oak

3
@amir bu programlama ile ilgili öznel bir soru olduğu için tamamen bu site için konudur - lütfen / faq
Jeff Atwood

1
Re, yerel değişkenler: Eski Java derleyicileri yerel ilan edip etmediğinize finalve buna göre optimize ettiğinize dikkat etti . Modern derleyiciler kendileri için çözebilecek kadar akıllıdır. En azından yerel değişkenlerde, finalkesinlikle insan okuyucuların yararınadır. Rutinleriniz çok karmaşık değilse, çoğu insan okuyucusu da kendileri için çözebilmelidir.
Solomon Yavaş

Yanıtlar:


67

Ben finalde seninle aynı şekilde yapıyorum . Bana göre yerel değişkenler ve yöntem parametreleri üzerinde gereksiz görünüyor ve faydalı ek bilgi sağlamıyor.

Önemli olan şeylerden biri, yöntemleri kısa ve temiz tutmak , her birinin tek bir görevi yerine getirmesidir . Bu nedenle yerel değişkenlerim ve parametrelerimin çok sınırlı bir kapsamı var ve sadece tek bir amaç için kullanılıyor. Bu, istemeden onları yeniden atama şansını en aza indirir.

Üstelik, bildiğiniz gibi, final(ilkel olmayan) bir değişkenin değerini / durumunu değiştiremeyeceğinizi garanti etmez. Yalnızca başlatıldıktan sonra bu nesneye referansı atayamazsınız. Başka bir deyişle, yalnızca ilkel veya değişmeyen türlerin değişkenleriyle sorunsuz çalışır. Düşünmek

final String s = "forever";
final int i = 1;
final Map<String, Integer> m = new HashMap<String, Integer>();

s = "never"; // compilation error!
i++; // compilation error!
m.put(s, i); // fine

Bu, birçok durumda kodun içinde ne olduğunu anlamayı kolaylaştıramadığı anlamına gelir ve bunun yanlış anlaşılması, aslında tespit edilmesi zor olan ince böceklere neden olabilir.


1
Düzenleme ile ilgili - Ben anlamın farkındayım final, teşekkür ederim :) ama kısa ve temiz yöntemler hakkında iyi bir nokta - Eğer yöntem yeterince kısaysa, bir değişkenin yeniden atanmamasının açık olduğunu düşünüyorum. finalanahtar kelimeyi değerlendirmek için daha az sebep .
Oak

Nihai parametrelere ve yerel değişkenlere ve yine de kısa ve temiz bir sözdizimine sahip olmamız harika olmaz mıydı? programmers.stackexchange.com/questions/199783/…
oberlies

7
"final (ilkel olmayan) bir değişkenin değerini / durumunu değiştiremeyeceğinizi garanti etmez. Yalnızca referansı başlattıktan sonra bu nesneye atayamayacağınızı garanti edemez." Temel olmayan = başvuru (Java'daki tek türler ilkel türlerdir ve başvuru türlerdir). Referans tip bir değişkenin değeri olan bir başvuru. Bu nedenle, referansı yeniden atayamazsınız = değeri değiştiremezsiniz.
user102008

2
Referans / durum düşüşü için +1. Java8'in yeni fonksiyonel yönlerinde kapanışlar oluşturmak için final değişkenini işaretleme değişkenlerinin gerekli olabileceğini unutmayın
Newtopian

Karşılaştırmalarınız @ user102008 tarafından işaret edildiği gibi önyargılıdır. Değişken atama değeri güncellemesiyle aynı değil
ericn

64

Java programlama stiliniz ve düşünceleriniz iyi - orada kendinizden şüphe duymanıza gerek yok.

Öte yandan, yerliler ve parametrelerle daha az faydalı buluyorum ve genellikle tekrar atanmayacak olsalar bile (bir iç sınıfta kullanılması gerektiğinde açık bir istisna olmakla birlikte) nihai olarak işaretlenmekten kaçınıyorum. ).

İşte bu yüzden finalanahtar kelimeyi kullanmalısınız . Bunu devlet SİZE o yeniden atanabilir asla biliyorum, ama hiç kimse bunu bilir. finalHemen kullanmak , kodunuzu küçümseyen kodları küçümser.


8
Eğer yönteminiz açıksa ve okuyucunun bileceği tek bir şey varsa. Son kelime sadece kodu okunamaz hale getirir. Ve eğer okunamıyorsa çok daha belirsiz
eddieferetro

4
@eddieferetro Aynı fikirde değil. Anahtar kelime finalniyetini belirtir, bu da kodu daha okunaklı hale getirir. Ayrıca, gerçek dünya koduyla uğraşmanız gerektiğinde, bunun nadiren bozulmamış ve net olduğunu fark edeceksiniz ve liberal olarak finalher yere s ekleyerek hataları saptamanıza ve eski kodu daha iyi anlamanıza yardımcı olacaktır.
Andres F.

4
Değişkenin asla değişmeyeceği ve kodunuzun bu gerçeğe dayanacağı "niyet" midir? Veya niyeti "bu yüzden bu değişken asla değişmez bu yüzden onu son olarak işaretliyorum" olur. Daha sonra işe yaramaz ve muhtemelen zararlı bir gürültü. Ve tüm yerlileri işaretlemeyi savunuyor göründüğünden , daha sonra yapıyorsunuz. Büyük -1.
user949300,

2
finalBir kod parçasında genellikle iyi bir şey olan niyetini belirtir, ancak görsel karışıklık eklemenin bedeli vardır. Programlamadaki çoğu şey gibi, burada bir takas var: değişkeninizin yalnızca ek bir ayrıntıya değecek kadar sadece bir kez kullanılacağı gerçeğini mi ifade ediyor?
christopheml

30

Mümkün olan her yerde final/ kullanmanın bir avantajı, constkod okuyucunuzun zihinsel yükünü azaltmasıdır.

Değer / referansın daha sonra hiçbir zaman değiştirilmediğinden emin olabilir. Bu yüzden hesaplamayı anlamak için değişikliklere dikkat etmesi gerekmez.

Tamamen işlevsel programlama dilleri öğrendikten sonra fikrimi değiştirdim. Boy, ne rahatlatırsa, her zaman başlangıç ​​değerini tutmak için bir "değişkene" güvenebilirseniz.


16
Peki, Java'da final(ilkel olmayan) bir değişkenin değerini / durumunu değiştiremeyeceğinizi garanti etmez. Yalnızca başlatıldıktan sonra bu nesneye referansı atayamazsınız.
Péter Török

9
Biliyorum, bu yüzden değer ve referans arasında ayrım yaptım. Konsept, değişken veri yapıları ve / veya saf işlevsellik bağlamında en faydalı olanıdır.
LennyProgrammers

7
@ PéterTörök İlkel türlere hemen yardımcı olur ve değişken nesnelere yapılan atıflara biraz yardımcı olur (en azından her zaman aynı nesneyle uğraştığınızı bilirsiniz!). Sıfırdan değiştirilemez şekilde tasarlanmış kodla uğraşırken son derece yararlıdır.
Andres F.

18

Ben düşünün finalkod gürültü olmaya yöntem parametreleri ve yerel değişkenlerde. Java yöntemi bildirimleri oldukça uzun olabilir (özellikle jeneriklerle birlikte) - daha fazla yapmaya gerek yoktur.

Birim testleri düzgün yazılır Eğer nedenle, asla, "zararlı" olduğu parametrelere atama alınmayı olacak aslında bir sorun. Görme netliği, ünite testlerinizin yetersiz kapsama alanına sahip olması nedeniyle toplanmamış olası bir hatadan kaçınmaktan daha önemlidir .

Parametrelere veya yerel değişkenlere atama yapılırsa derlemeyi kırmak üzere yapılandırılabilen FindBugs ve CheckStyle gibi araçlar.

Tabii ki, onları nihai hale getirmeniz gerekiyorsa , örneğin değeri anonim bir sınıfta kullandığınız için, o zaman sorun değil - bu en basit ve en temiz çözüm.

Parametrelerinize ilave anahtar kelimeler eklemenin ve dolayısıyla IMHO'nun bunları kamufle etmenin belirgin etkisinin dışında, yöntem parametrelerine son olarak eklemek, yöntem gövdesindeki kodun daha az okunabilir olmasına neden olur, bu da kodu "daha iyi" yapmaktır mümkün olduğu kadar okunabilir ve basit olmalıdır. Kararlı bir örnek için, vakayı duyarsızca çalışması gereken bir yöntemim olduğunu söyleyin.

Olmadan final:

public void doSomething(String input) {
    input = input.toLowerCase();
    // do a few things with input
}

Basit. Temiz. Neler olduğunu herkes biliyor.

Şimdi 'final' ile, seçenek 1:

public void doSomething(final String input) {
    final String lowercaseInput = input.toLowerCase();
    // do a few things with lowercaseInput
}

Parametrelerin yapılması finalkodlayıcıyı kodun asıl değer ile çalıştığını düşünmekten daha aşağıya koyarken , kodun aşağıya kullanılması inputyerine, kullanmaması lowercaseInputgereken ve karşı korunamayacağı kadar eşit bir risk vardır. t kapsam dışına çıkarmak (hatta atamak nulliçin inputbile yine de yardımcı olacağını ise).

'Final' ile, seçenek 2:

public void doSomething(final String input) {
    // do a few things with input.toLowerCase()
}

Şimdi sadece daha da fazla kod gürültüsü yarattık ve toLowerCase()n kere çağırmak zorunda kaldığımız bir performans hitini getirdik .

'Final' ile, seçenek 3:

public void doSomething(final String input) {
    doSomethingPrivate(input.toLowerCase());
}

/** @throws IllegalArgumentException if input not all lower case */
private void doSomethingPrivate(final String input) {
    if (!input.equals(input.toLowerCase())) {
        throw new IllegalArgumentException("input not lowercase");
    }
    // do a few things with input
}

Kod gürültüsü hakkında konuşun. Bu bir tren kazası. Yeni bir yöntemimiz var, gerekli bir istisna bloğu var, çünkü diğer kodlar onu yanlış çağırdı. İstisna için daha fazla birim testi. Hepsi bir basit ve IMHO tercih ve zararsız, çizgi önlemek için.

Ayrıca, yöntemlerin o kadar uzun olmaması gerektiğine dair bir sorun da var; görsel olarak kolayca alamaz ve bir bakışta parametreye atama yapıldığını bilirsiniz.

Bunun bir parametreye atarsanız bunu her tercihen ilk satırı, yöntemde erken veya düz temel girdi etkin kontrol ettikten sonra yapmak iyi bir uygulama / stil sizce değiştirilmesi için bütün içinde tutarlı bir etkiye sahiptir yöntemle, yöntem. Okuyucular, herhangi bir ödevin açık olmasını (imza beyannamesi yakınında) ve tutarlı bir yerde beklemelerini bilir; bu da final eklemenin kaçınmaya çalıştığı sorunu büyük ölçüde azaltır. Aslında nadiren parametrelere atarım, ancak yaparsam bunu her zaman bir yöntemin en üstünde yaparım.


Ayrıca, finalaslında ilk bakışta göründüğü gibi sizi korumadığını da unutmayın:

public void foo(final Date date) {
    date.setTime(0); 
    // code that uses date
}

final Parametre türü ilkel veya değişken olmadıkça sizi tamamen korumaz.


Son durumda, finalaynı durumla ilgili olduğunuz kısmi garantiyi sağlar Date. Bazı garantiler hiçbir şeyden iyidir (eğer bir şey varsa, sıfırdan değişmeyen sınıflar için tartışıyorsunuz!). Her durumda, pratikte söylediklerinizin çoğu, varsayılan olarak değiştirilemeyen dilleri etkilemelidir, ancak öyle değildir, yani sorun değildir.
Andres F.

“Aşağı doğru kod girerek girdi kullanabilir” riskine işaret etmek için +1. Yine de, finalyukarıdaki gibi durumlar için onları nihai hale getirmeme olasılığı olan parametrelerimin olmasını tercih ederim . Bu, bir anahtar kelimeyle imzayı spam göndermeye değmez.
maaartinus

7

Tutulmanın finalher yerel değişkenin önüne koyulmasına izin veriyorum çünkü programı okumayı daha kolay hale getirmeyi düşünüyorum. Parametrelerle yapmıyorum, çünkü parametre listesini mümkün olduğunca kısa tutmak istiyorum, ideal olarak bir satıra sığması gerekiyor.


2
Ayrıca, parametreler için, bir parametre atanmışsa derleyiciye bir uyarı veya hata verebilirsiniz.
ayık

3
Tam tersine, sadece kod kümesini tutarken okumayı zor buluyorum.
Steve Kuo

3
@ Steve Kuo: Sadece tüm değişkenleri hızlıca bulmamı sağlıyor. büyük kazanç yok, ancak yanlışlıkla yapılan ödevleri engellemekle birlikte 6 karaktere değiyor. varNihai olmayan değişkenleri işaretlemek gibi bir şey olsaydı daha mutlu olurdum . YMMV.
maaartinus 12:13

1
@maaartinus Hakkında Anlaşıldı var! Maalesef Java’da varsayılan değil ve dili değiştirmek için artık çok geç. Bu nedenle, küçük yazma sıkıntılarına katlanmak için hazırım final:)
Andres F.

1
@maaartinus Anlaşıldı. (Yerel) değişkenlerimin yaklaşık% 80-90'ının başlangıçtan sonra değiştirilmelerinin gerekmediğini biliyorum. Dolayısıyla, bunların% 80-90 olması finalsadece% 10-20 bir gerekir, oysa önüne anahtar kelime var...
JimmyB
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.