Bir sabitin değeri zaman içinde değişebilir mi?


28

Geliştirme aşamasında, aynı çalışmada sabit olması gereken ancak zaman içinde değiştirilmesi gerekebilecek belirli değişkenler vardır. Örneğin, a booleanhata ayıklama modunu işaret etmek için programda normalde yapmadığımız şeyleri yaparız.

Bu değerleri sabit bir şekilde, yani final static int CONSTANT = 0Java'da içermesi kötü bir tarz mıdır ? Sabit bir sürenin çalışma süresi boyunca aynı kaldığını biliyorum, ancak planlanmamış değişiklikler dışında tüm gelişim boyunca da aynı olması mı gerekiyor?

Benzer soruları aradım, ancak benimkiyle tam olarak eşleşen hiçbir şey bulamadım.


11
Merak ediyorum, neden bunları değiştirmenin kötü bir tarz olduğuna inanıyorsun?
Vincent Savard

36
Fiziksel özellikleri bilinen matematiksel değerlere sahip sabitlerle modellemediğiniz sürece, her şey bir anda değişebilir.
Berin Loritsch

19
yazılım yumuşak .
Erik Eidt

10
@GregT Ben katılmıyorum. finalsize derleyici tarafından verilen ve programın değeri değiştirmeyeceği garantisini verir. Bunun nedeni, programcının kaynak kodda verilen değeri değiştirmek isteyebilmesi olabilir.
Alexander - Monica

10
Tam bir cevabı ifade etmek için çok fazla zaman yok, ancak meslektaşlarınızın endişelerinin sabitler ile çok fazla değil, sabitler olarak tezahür ettirme eğiliminde olabilecek yapılandırma değerlerinin kod satırına girmesinden şüpheleniyorum. ... Sabitler, gravityoyunun ortasında / koşusunda yanlışlıkla görevlendirmek gibi aptalca hatalara karşı sizi korur . gravityHer gezegende aynı olduğu anlamına gelmez . Bu, sağlıklı bir çözümün gravitysabit hale getirilmesi , ancak planetilgili kapsamın başlangıcında bir dosyadan veya veritabanından alınması anlamına gelir.
svidgen

Yanıtlar:


6

Java'da statik son sabitler, derleyici tarafından değerleri olarak bunları kullanan koda kopyalanabilir . Bunun bir sonucu olarak, kodunuzun yeni bir sürümünü yayınlarsanız ve sabiti kullanan bir aşağı akış bağımlılığı varsa, bu koddaki sabit aşağı akış kodu yeniden derlenmedikçe güncellenmez. Kaynak kodu doğru olsa bile, ikili kod değil, yeni değeri bekleyen kodla bu sabitten yararlanırlarsa, bu bir sorun olabilir.

Bu, Java tasarımındaki bir siğildir, çünkü kaynak uyumluluğu ve ikili uyumluluğun aynı olmadığı çok az durumdan biri (belki de tek vaka). Bu durum dışında, bağımlılığın kullanıcıları yeniden derlemek zorunda kalmadan, yeni bir API uyumlu sürümle bir bağımlılığı değiştirebilirsiniz. Açıkçası, Java bağımlılıklarının genel olarak yönetilme şekli göz önüne alındığında bu son derece önemlidir.

Daha da kötüsü, kodun yararlı hatalar üretmek yerine sessizce yanlış şeyi yapmasıdır. Bir bağımlılığı, uyumsuz sınıf veya yöntem tanımlarına sahip bir sürümle değiştirmek isteseydiniz, en azından sorunun ne olduğuna dair iyi ipuçları veren sınıflayıcı veya çağrı hataları alırsınız. Değerin türünü değiştirmediyseniz, bu sorun sadece gizemli çalışma zamanı yanlış davranışları olarak görünecektir.

Daha sinir bozucu olanı, bugünün JVM'lerinin çalışma zamanındaki tüm sabitleri performans cezası olmadan (muhtemelen yine de yüklenmekte olan sabitleri tanımlayan sınıfı yüklemeye gerek kalması dışında) JIT'lerden önceki günlerden itibaren kolayca yüklemeleri olabilir . Ve dili değiştiremezler çünkü o zaman önceki derleyicilerle derlenmiş kod doğru olmaz. Bugece-uyumluluk tekrar grev.

Bütün bunlardan dolayı, bazı insanlar hiçbir zaman statik bir nihai değer değiştirmeyi tavsiye etmiyorlar. Bilinmeyen zamanlarda yaygın şekilde dağıtılabilen ve bilinmeyen şekillerde güncellenebilen kütüphaneler için bu iyi bir uygulamadır.

Kendi kodunuzda, özellikle bağımlılık hiyerarşisinin tepesinde, muhtemelen bundan kurtulacaksınız. Ancak bu durumlarda, kamuya açık (veya korunmuş) olmak için sabitin gerçekten gerekli olup olmadığını düşünün. Sabit sadece paket görünürlüğüyse, koşullarınıza ve kod standartlarınıza bağlı olarak, paketin her zaman bir kerede yeniden derleneceği ve sorunun çözüldüğü için makul olur. Eğer sabit özelse, hiçbir probleminiz olmaz ve istediğiniz zaman değiştirebilirsiniz.


85

Kaynak kodunuzdaki, constbeyan edilen genel sabitler dahil, herhangi bir şey , yazılımın yeni bir sürümüyle değişebilir.

Anahtar kelimeler const(veya finalJava’da), derleyiciye, bu değişkenin programın bu örneği çalışırken değişmeyeceğini bildirmek için vardır . Daha fazlası değil. Bir sonraki bakıcıya mesaj göndermek istiyorsanız, kaynak için bir yorum kullanın, bunun için oradalar.

// DO NOT CHANGE without consulting with the legal department!
// Get written consent form from them before release!
public const int LegalLimitInSeconds = ...

Gelecekteki benliğinizle iletişim kurmanın daha iyi bir yolu.


11
Bu yorumu gelecekteki benliğe gerçekten sevdim.
GregT

4
TaxRateolmak publicbeni tedirgin ediyor. Kesin olarak sadece satış departmanının bu değişiklikten etkilendiğini ve ayrıca bize vergi alan tedarikçilerimizi de bilmemeyi isterim. Bu yorum yazıldığından beri kod tabanında neler olduğunu kim bilebilir?
candied_orange

3
@IllusiveBrian, sabitlerin kullanılmasını eleştirmiyordu. Güncel olmak için bir yoruma güvenme konusunda uyarı yapıldı. Bir şeyi değiştirmeden önce her zaman bir şeyin nasıl kullanıldığından emin olun.
candied_orange 08:18

8
Java için bu iyi bir tavsiye . Diğer dillerde farklı olabilir. Örneğin, const değerlerinin C # 'daki çağrı sitesine bağlanma şekli nedeniyle, public constalanlar yalnızca Math.pi gibi asla değişmeyecek şeyler için kullanılmalıdır. Bir kitaplık oluşturuyorsanız, geliştirme sırasında veya yeni bir sürümle değişebilecek şeyler public static readonly, kitaplığınızın kullanıcılarında sorunlara yol açmayacak şekilde olmalıdır.
GrandOpener

6
Farklı bir örnek seçmelisin ... para değerleri asla kayan nokta olmamalı!
corsiKa

13

Sabitlerin iki yönünü ayırt etmemiz gerekir:

  • Geliştirme zamanında bilinen ve daha iyi korunma amacıyla verdiğimiz değerler için isimler ve
  • derleyici için mevcut değerler.

Ve bununla ilgili üçüncü tür bir tür var: değeri değişmeyen değişkenler, yani bir değerin adları. Bu değişmez değişkenler ile bir sabit arasındaki fark, değerin belirlendiği / atandığı / başlatıldığı zamandır: değişken, çalışma zamanında başlatılır, ancak geliştirme sırasında bir sabitin değeri bilinir. Bu ayrım biraz çamurludur, çünkü geliştirme sırasında bir değer bilinebilir, ancak aslında yalnızca başlatma sırasında yaratılır.

Ancak bir sabitin değeri derleme zamanında biliniyorsa, derleyici bu değerle hesaplamalar yapabilir. Örneğin, Java dili sabit ifadeler kavramına sahiptir . Sabit ifade, yalnızca ilkel veya dizgenin değişmezlerinden, sabit ifadelerdeki işlemlerden (örneğin döküm, toplama, dize birleştirme) ve sabit değişkenlerden oluşan herhangi bir ifadedir. [ JLS §15.28 ] Sabit bir finaldeğişken, sabit bir ifadeyle başlatılan bir değişkendir. [JLS §4.12.4] Java için bu bir derleme zamanı sabitidir:

public static final int X = 7;

Birden fazla derleme ünitesinde sabit bir değişken kullanıldığında ve ardından bildirim değiştirildiğinde bu ilginç hale gelir. Düşünmek:

  • A.java:

    public class A { public static final int X = 7; }
  • B.java:

    public class B { public static final int Y = A.X + 2; }

Şimdi bu dosyaları derlediğimizde B.classbytecode bir alan ilan edecek Y = 9çünkü B.Ysabit bir değişken.

Ancak, A.Xdeğişkeni farklı bir değere (örneğin X = 0) değiştirdiğimizde ve sadece A.javadosyayı yeniden derlediğimizde , B.Yhala eski değere işaret eder. Bu durum A.X = 0, B.Y = 9kaynak kodundaki bildirimlerle tutarsız. Mutlu hata ayıklama!

Bu, sabitlerin asla değiştirilmemesi gerektiği anlamına gelmez. Sabitler, kaynak kodunda açıklama olmadan görünen sihirli sayılardan kesinlikle daha iyidir. Ancak, değer kamu sabitler genel API parçasıdır . Bu, Java'ya özgü değildir, ancak C ++ ve ayrı derleme birimleri içeren diğer dillerde de oluşur. Bu değerleri değiştirirseniz, tüm bağımlı kodları yeniden derlemeniz gerekecektir, yani temiz bir derleme yapmanız gerekecektir.

Sabitlerin niteliğine bağlı olarak, geliştiriciler tarafından yanlış varsayımlara yol açmış olabilirler. Bu değerler değiştirilirse, bir hata tetikleyebilir. Örneğin, belirli bit desenleri oluşturacak şekilde bir sabitler kümesi seçilebilir, örneğin public static final int R = 4, W = 2, X = 1; Bunlar gibi farklı bir yapı oluşturacak şekilde değiştirilirse, R = 0, W = 1, X = 2o zaman varolan kod boolean canRead = perms & Ryanlış olur. Ve sadece ortaya çıkacak eğlencenin Integer.MAX_VALUEdeğişeceğini düşünün ! Burada bir düzeltme yok, bazı sabitlerin değerinin gerçekten önemli olduğunu ve basitçe değiştirilemeyeceğini unutmamak önemlidir.

Ancak, sabitlerin çoğunun değişmesi, yukarıdaki kısıtlamalar göz önüne alındığı sürece, iyi olacak. Belirli bir değerin değil, anlamın ne zaman önemli olduğu, değişmesi güvenlidir. Bu gibi tunables için durum örneğin edilir BORDER_WIDTH = 2ya TIMEOUT = 60; // secondsveya şablonlar gibi API_ENDPOINT = "https://api.example.com/v2/"- gerçi muhtemelen bunlardan bazılarının veya tümünün yapılandırma dosyaları yerine kodunda belirtilen gerektiğini.


5
Bu analizi seviyorum. Bunu şöyle okurum: Nasıl kullanıldığını anladığınız sürece sabiti değiştirmekte özgürsünüz.
candied_orange,

+1 C # ayrıca kamu sabitleri ile aynı konuda “acı çekiyor”.
Reginald Blue

6

Sabit, yalnızca uygulama çalışma zamanının ömrü boyunca sabit olması garanti edilir . Bu doğru olduğu sürece, dil özelliğinden yararlanmamak için hiçbir sebep yoktur. Sadece aynı amaç için bir sabit-derleyici bayrakları kullanmanın sonuçlarının ne olduğunu bilmeniz gerekir:

  • Sabitler uygulama alanı kaplar
  • Derleyici bayrakları yok
  • Sabitler tarafından kapatılan kod, modern yeniden düzenleme araçlarıyla güncellenebilir ve değiştirilebilir
  • Derleyici bayrakları tarafından kapatılan kod

Şekillerin sınırlayıcı kutularını çizmeye yarayan bir uygulamayı sürdürerek, nasıl çizildiklerine dair hata ayıklayabilmemiz için bir sorunla karşılaştık. Yeniden düzenleme işleminden sonra, derleyici bayrakları tarafından kapatılan tüm kodlar derlenmez. Ondan sonra bilerek derleyici bayraklarımızı uygulama sabitlerine çevirdik.

Bunun değiş tokuş olduğunu göstermek için söylüyorum. Birkaç booleanın ağırlığı, uygulamanın hafızasının tükenmesine ya da fazla yer kaplamasına neden olmayacaktı. Sabitiniz gerçekten, kodunuzdaki her şey için bir tutamağı olan büyük bir nesne ise, bu doğru olmayabilir. Artık ihtiyaç duyulmadığında bir nesneye ait olan tüm referansları kaldırmamaya özen gösterirse, nesneniz bir bellek sızıntısı kaynağı olabilir.

Kullanım durumunu ve neden sabitleri değiştirmek istediğinizi değerlendirmeniz gerekir.

Ben basit bir battaniye ifadesi hayranı değilim, fakat genel olarak kıdemli meslektaşınız haklı. Sık sık değişecek bir şey varsa, yapılandırılabilir bir öğe olması gerekebilir. Örneğin, IsInDebugMode = truebazı kodların kırılmasını önlemek istediğinizde meslektaşınızı sürekli olarak ikna edebilirsiniz . Ancak, bazı şeylerin bir uygulamayı yayınladığınızdan daha sık değişmesi gerekebilir. Bu durumda, uygun bir zamanda bu değeri değiştirmenin bir yolunu gerekir. Bir örneğini alabilirsiniz TaxRate = .065. Bu, kodunuzu derlerken doğru olabilir, ancak yeni yasalar nedeniyle uygulamanızın bir sonraki sürümünü yayınlamadan önce değişebilir. Bu, bazı depolama mekanizmalarından (dosya veya veritabanı gibi) güncellenmesi gereken bir şeydir.


Derleyici bayrakları derken ne demek istiyorsun? Muhtemelen C işlemcisi ve benzer derleyici özellikleri, makroları / tanımlamaları ve komutları destekler #ifdef? Bunlar kaynak kodun metinsel ikamesine dayandığından , programlama dilinin anlambiliminin bir parçası değildir. Java'nın bir ön işlemcisi olmadığını unutmayın.
amon

@ amon, Java olmayabilir, ancak birkaç dilde var. #ifdefBayrakları kastediyorum . C'nin anlambiliminin bir parçası olmasalar da C # 'nın bir parçasıdır. Dil agnostisizminin daha geniş bağlamı için yazıyordum.
Berin Loritsch

Sanırım "hafıza kaybı" argümanı tartışılmaz. Astar içi ve ağaç sallama, herhangi bir sürüm modu iyileştiricisinde oldukça evrensel bir adımdır.
Alexander - Monica

@Alexander, katılıyorum. Bu farkında olmak bir şey.
Berin Loritsch

1
"Sabitler uygulama alanını kaplar" - yalnızca bir kilobayt veya iki belleğe sahip bir mikroişlemci için gömülü bir uygulama geliştirmiyorsanız, böyle şeyler hakkında düşünmemelisiniz bile.
vsz

2

const, #defineYa finalbir derleyici ipucu (yani nottur #defineaslında bir ipucu değil, onun bir makro ve çok daha güçlü). Bir programın yürütülmesi sırasında değerin değişmeyeceğini ve çeşitli optimizasyonların yapılabileceğini gösterir.

Bununla birlikte, bir derleyici ipucu olarak derleyici, programlayıcı tarafından her zaman beklenmeyecek şeyler yapar. Özellikle, Javac bir iç fonksiyon static final int FOO = 42;böylece hiçbir yerinde FOOkullanılırsa, gerçek derlenmiş bayt kod okuyacaktır 42.

Birisi diğer derleme ünitesini (.java dosyası) tekrar derlemeden değeri değiştirene ve 42bayt kodunda kalanlara kadar bu çok büyük bir sürpriz değil (bkz. Javac'ın statik son değişkenlerin satırını devre dışı bırakmak mümkün mü? ).

Bir şey yapmak static final, bunun ve sonsuza dek devam edeceği anlamına gelir ve onu değiştirmek, gerçekten büyük bir anlaşmadır - özellikle de başka bir şeyse private.

Gibi şeyler için sabitler final static int ZERO = 0bir sorun değildir. final static double TAX_RATE = 0.55(para ve çifte olmak bir yana, kötüdür ve BigDecimal'i kullanmalıdır, fakat sonra bu ilkel değildir ve dolayısıyla satır içi değildir) bir problemdir ve kullanıldığı yere dikkatle incelenmelidir.


SIFIR küçük değerleri için.

3
is a problem and should be examined with great care for where it is used.O niçin bir problem olsun ki?
Alexander - Monica

1

Adından da anlaşılacağı gibi, çalışma süreleri boyunca sabitler değişmemelidir ve benim görüşüme göre sabitler uzun süre değişmeyecek şekilde tanımlanır ( daha fazla bilgi için bu SO sorusuna bakabilirsiniz) .

Bayraklara ihtiyaç duyulduğunda (örneğin geliştirme modu için) bunun yerine config modunu veya startup parametresini kullanmalısınız (birçok IDE proje bazında başlangıç ​​parametresini konfigüre etmeyi destekler; bu dokümantasyona bakın) - bu modu etkinleştirmek için - Bu şekilde, böyle bir mod kullanma esnekliğini korursunuz ve kod her üretken olduğunda değiştirmeyi unutamazsınız.


0

Eserler arasında değişebilmek, kaynak kodunuzda bir sabit tanımlamanın en önemli noktalarından biri!

Sabit, kaynak kodunuzun kullanım ömrü boyunca ihtiyacınız olduğunda değeri değiştirmek için size iyi tanımlanmış ve belgelenmiş (bir anlamda) bir konum sağlar. Aynı zamanda, bu konumdaki sabitin değiştirilmesinin, neyi temsil ettiğiin tüm oluşumlarını değiştireceği vaadidir.

Olumsuz örnek olarak: o olurdu değil bir sabit olması mantıklı TRUEiçin evalutes trueaslında sahip bir dilde trueanahtar kelime. TRUE=falseZalim şakalar dışında asla, asla, bir kere bile olmaz .

Tabii ki sabitlerin başka kullanımları da vardır, örneğin kod kısaltması ( CO_NAME = 'My Great World Unique ACME Company'), çoğaltmadan ( PI=3.141) kaçınılması , kuralları ( TRUE=1) veya her neyse ayarlanması , ancak sabiti değiştirmek için tanımlanmış bir konuma sahip olması kesinlikle en belirgin olanlardan biridir.

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.