Neden Java'da String.Empty yok?


260

Dize değişmezi her yazdığımda "", dize havuzunda aynı String nesnesine başvurulduğunu anlıyorum .

Ama neden String API bir içermiyor public static final String Empty = "";, bu yüzden referansları kullanabilir String.Emptymiyim?

Derleyici varolan Dizeye başvurmayı bildiğinden ve yeniden kullanım için önceden oluşturulmuş olup olmadığını kontrol etmek zorunda olmadığından, en azından derleme zamanında tasarruf ederdi, değil mi? Ve kişisel olarak, dize değişmezlerinin çoğalmasının, özellikle küçük olanların, çoğu durumda bir "kod kokusu" olduğunu düşünüyorum.

Yani String.Empty arkasında bir Büyük Tasarım Nedeni vardı, ya da dil yaratıcıları sadece görüşlerimi paylaşmadı mı?


5
Aidanc: Bence sen gibi şeyler durumları kastediyor outputBlah = "", o da muhtemelen tercih something == String.Emptyüzerinde something.Length > 0de (eğer boş çek atlayın.)
Skurmedel

2
@Aidanc - "Boşluk" dizesini kontrol etme işlevi değil, Collections.EMPTY_SET gibi "boş bir üye" arıyordu .
Tim Stone

2
@Aidanc: Buna ilham veren şey aslında 'TextBox.setText ("");'.
Tom Tresansky

3
Bir String.isEmpty()fonksiyon var ... neden istiyorsun String.EMPTY?
Buhake Sindi

8
String.isEmpty()boş bir dize döndürmez.
Steve Kuo

Yanıtlar:


191

String.EMPTY12 karakter ve ""iki karakterdir ve her ikisi de çalışma zamanında bellekte tam olarak aynı örneğe başvurur. String.EMPTYDerleme zamanında neden tasarruf edeceğinden tam olarak emin değilim , aslında bunun ikinci olacağını düşünüyorum.

Özellikle Strings'nin değişmez olduğu düşünüldüğünde, ilk önce boş bir String alabilir ve üzerinde bazı işlemler gerçekleştirebilirsiniz - en iyisi a kullanmak StringBuilder(veya StringBufferiş parçacığı için güvenli olmak istiyorsanız) ve bunu bir String'e dönüştürmek gibi.

Güncelleme
Yorumunuzdan soruya:

Buna ilham veren şey aslında TextBox.setText("");

Uygun sınıfınızda bir sabit sağlamanın tamamen meşru olacağına inanıyorum:

private static final String EMPTY_STRING = "";

Ve sonra kodunuzdaki gibi referans olarak

TextBox.setText(EMPTY_STRING);

Bu şekilde en azından IDE'nizdeki Dizeyi veya benzer bir şeyi doldurmayı unutmak yerine boş bir Dizgi istediğinizi açıkça belirlersiniz.


14
Seni hala + 1'leyeceğim, ancak kendimi kirli hissediyorum çünkü StringBuilderon kişiden dokuzu kez StringBuilderbirleştirmeden ziyade kullanmanın tamamen uygunsuz olduğundan bahsetmeden bahsetmiştin .
Randolpho

85
Ben daha açık olduğu için string.empty tercih eğilimindedir. Ayrıca, "" ve "" "gibi şeyleri görsel olarak ayırt etmenin daha zor olabileceği hız durumları vardır. Sonunda, diğerlerinin de belirttiği gibi, gerçek işten sıkıldığımızda tartışmamız için bize yem veren bu anlamsız stil şeylerden sadece biri. =)
JohnFx

@Nodel M: Derleme zamanı ile ilgili olarak, aynı dize değerine sahip 2 farklı kaynak dosyasında tanımlanmış 2 dize değişmezi varsa, derleyici ikincisine çarptığında bunu anlamak için bir tür kontrol yapması gerektiğini varsayıyorum " hey, bu dizeyi arkadan zaten biliyorum ". Kuşkusuz java derleyicisinde uzman değilim, ama bu nasıl OLAMAZ? Ve bu kontrolü atlamanın derleme zamanlarında küçük bir iyileşme ile sonuçlanacağını düşünürüm.
Tom Tresansky

@Tom - Ben inanıyorum dize stajyer zaman derleme değil, derleme değil, yani aslında başka bir dosyada bir sabit olarak boş dize varsa, derleyici Dize değişmez çözmek için bu sınıfa başvurması gerekir.
Noel M

1
@Randolpho Dize birleştirme kullanırken aslında başlık altında bir StringBuilder kullanıyorsunuz.
whiskysierra

133

kullanım org.apache.commons.lang.StringUtils.EMPTY


30
Boş bir "" programından çok daha hoş ve okunması kolay görünüyor. Umarım sadece ben değil.
Lakatos Gyula

2
@LakatosGyula - Sanırım bu olabilir (sadece sen). Yetkin Java programcılarının okuma problemi yoktur ""... ve büyük olasılıkla alana özgü bir anlamı EMPTYolan özel durumlar dışında kullanımı hakkında yüksek sesle itiraz ederler EMPTY. (Ve bu gibi durumlarda, muhtemelen daha uygun bir isim vardır.)
Stephen C

14
@LakatosGyula Sadece sen değil. Java'dan .NET geliştirmeye gittim ve String.Empty, çerçevede bulmaktan memnun olduğum bir özellikti. Boş bir alıntı seti üzerindeki açık doğasını seviyorum.
yohohoho

64
@StephenC Boş bir "" gördüğümde ilk şey aklımda bir hata olduğunu, birisi fonksiyonu vb bitirmediğini atlar. String.EMPTY ile tam olarak geliştirici boş bir dize döndürmek niyetinde biliyorum.
Lakatos Gyula

1
Ayrıca linter "falan filan filan yerine adlandırılmış bir sabit kullanın" dediğinde tüm zamanlar için yararlıdır. Her programcı "" sihir olmadığını bilir, ancak bunu müşteriye açıklamak zorunda değildir.
LizH

28

Boş değerler hakkında endişelenmeden boş dizeyle karşılaştırmak isterseniz, aşağıdakileri yapabilirsiniz.

if ("".equals(text))

Sonuçta en açık olduğuna inandığınız şeyi yapmalısınız. Çoğu programcı "", birinin içine herhangi bir şey koymayı unuttuğu bir dize değil, boş dize anlamına gelir.

Bir performans avantajı olduğunu düşünüyorsanız, bunu test etmelisiniz. Kendiniz için test etmeye değer olduğunu düşünmüyorsanız, gerçekten buna değmeyeceğine dair iyi bir gösterge.

Dil, 15 yıldan fazla bir süre önce tasarlandığında çözülmüş bir sorunu çözmeye çalışmak gibi görünüyor.


1
Partiye oldukça geç kaldım, ancak Java dizeleri değişmez olduğundan, bir JVM içindeki tüm boş dizelerin aynı String nesnesine sadece farklı referanslar olduğuna inanıyorum. Yani sadece aşağıdakiler de doğrudur: if ("" == text)
Ajoy Bhatia

12
@AjoyBhatia Sorun, yeni boş dizeler oluşturabilmenizdir. if ("" == new String())yanlış. Daha iyi bir testif(text.isEmpty())
Peter Lawrey

1
@AjoyBhatia - Yalnızca dizeler staj edilmişse. stackoverflow.com/questions/10578984/what-is-string-interning
Davor

9

Gerçekten bir String.EMPTY sabiti istiyorsanız, projenizde "Sabitler" (örneğin) adlı bir statik statik son sınıf oluşturabilirsiniz. Bu sınıf, boş String de dahil olmak üzere sabitlerinizi koruyacaktır ...

Aynı fikirde, SIFIR, ONE int sabitleri oluşturabilirsiniz ... Tamsayı sınıfında mevcut değildir, ancak yorum yaptığım gibi, yazmak ve okumak bir acı olacaktır:

for(int i=Constants.ZERO; ...) {
    if(myArray.length > Constants.ONE) {
        System.out.println("More than one element");
    }
}

Vb.


8

Apache StringUtils de bu sorunu giderir.

Diğer seçeneklerin hataları:

  • isEmpty () - null güvenli değil. Dize null olursa, bir NPE atar
  • length () == 0 - yine null güvenli değil. Beyaz boşluk dizelerini de dikkate almaz.
  • BOŞ sabiti ile karşılaştırma - Boşta olmayabilir. Boşluk sorunu

Granted StringUtils, sürüklenecek başka bir kütüphanedir, ancak çok iyi çalışır ve boş zamanlar veya NPE'leri incelikle işlemek için çok fazla zaman ve güç tasarrufu sağlar.


3
böylece ... tek güvenli seçenek korkunç Yoda durumdur görünüyor: "".equals(s)?
Yalan Ryan

8

Sadece "dizelerin bellek havuzu tam anlamıyla yeniden kullanılır, dava kapandı" demeyin. Derleyicilerin kaputun altında yaptıkları burada mesele değil. Soru, özellikle alınan oyların sayısı göz önüne alındığında makul.

Bu simetri ile ilgilidir , onsuz API'lerin insanlar için kullanımı daha zordur. İlk Java SDK'ları bu kuralı kötü bir şekilde görmezden geldi ve şimdi biraz geç. İşte başımın üstünde birkaç örnek, "favori" örneğinizde çipleme yapmaktan çekinmeyin:

  • BigDecimal.ZERO, ancak AbstractCollection.EMPTY, String.EMPTY yok
  • Array.length ancak List.size ()
  • List.add (), Set.add () ancak Map.put (), ByteBuffer.put () ve unutmayalım StringBuilder.append (), Stack.push ()

List parametresi length () adını kullansanız bile, bir yöntem olduğundan paranteziniz olması gerekir. Array.length, yalnızca Diziler değişmez olduğu için çalışan genel bir son değişkendir. Böylece hala Array.length ve List.length () yöntemlerine sahip olursunuz. Bunun daha kafa karıştırıcı ve hataya açık olduğunu iddia ediyorum. .Append () ve .push () 'e gelince, benzer görevleri yerine getirirken uygun şekilde adlandırıldıklarını düşünüyorum. Dize eklemek tam olarak yaptığınız şeydir, ancak bir Yığın "eklemezsiniz", değerleri itersiniz ve pop yaparsınız. Ve StringBuilder.push (), mümkün olmayan StringBuilder.pop () anlamına gelir.
Craig Parton

Şablonlardan / jeneriklerden gelen tutarlı arayüzler algoritmalara da yardımcı olur. Bir algoritmanın bir koleksiyonun uzunluğuna ihtiyacı varsa, tek istediğimiz uzunluk (T) veya T.length () olur. Benzer şekilde, bir yığının, listenin veya dizenin sonuna ekleme evrensel bir add () veya append () tarafından yapılabilir. Java'daki dizinin açık uzunluk özelliğine sahip değişmez / yerleşik tip olduğunu belirtmişsinizdir. Bu iyi, derleyicinin uzunluk (T) veya T.length () için kod işleyemeyeceği veya üretemeyeceği anlamına gelmez. Kotlin, çeşitli durumlar için bir dizi içsel yöntem üretir.
Slawomir

Ancak tutarlı bir şekilde adlandırılmış length () yöntemi yalnızca uzunluğu kontrol etmemizi sağlar. Bu ne kadar faydalı? Hedefiniz Listeler ve Diziler'i bir arabirim aracılığıyla bir şekilde kullanılabilir hale getirmek için soyutlamaksa, verileri okumak veya yazmak için tutarlı bir şekilde de ihtiyacınız vardır. Şimdi get (), set () ve add () yöntemlerini oluşturmanız gerekir. Temel olarak, Dizinin daha az işlevsel bir Liste görünümünü oluşturuyorsunuz. Arrays.asList () kullanılabilir, kullanımı kolay ve hafif olduğundan, tekerleği neden yeniden icat ettiniz? Diziler, Listeler, StringBuilders ve Yığınların belirli bir amacı vardır. Arayüzünüzü en uygun olanı kullanmak üzere tasarlamak daha iyi görünüyor.
Craig Parton

5

Bütün bu ""değişmezler aynı nesnedir. Neden tüm bu ekstra karmaşıklığı? Yazmak sadece daha uzun ve daha az net (derleyicinin maliyeti minimumdur). Java'nın dizeleri değişmez nesneler olduğu için, muhtemelen bir etkinlik şey dışında aralarında ayrım yapmak için hiçbir zaman ihtiyaç yoktur, ancak boş dize hazır bilgisi ile bu büyük bir sorun değildir.

Gerçekten bir EmptyStringsabit istiyorsanız , kendiniz yapın. Ancak tek yapacağı şey daha ayrıntılı kodları teşvik etmek; Orada olacak asla bunu yaparken herhangi bir yararı.


27
x = String.Emptyniyeti daha iyi iletir x = "". İkincisi tesadüfi bir ihmal olabilir. Olduğunu söylemek asla herhangi yararı yanlış olduğunu.
Jeffrey L Whitledge

@Jeffrey: Özellikle katıldığımı sanmıyorum. Sanırım zor ve hızlı bir kuralın olmadığı bu şeylerden biri.
Donal Fellows

Evet, java derleyicisinin dize değişmezlerinin dize havuzunda yeni bir örnek oluşturmadan önce var olup olmadığını kontrol ettiğini belirtmek önemlidir.
rds

1
@Jeffrey - bunun çok eski ve öznel bir tartışma olduğunu bilmek. x = String.Emptyniyet taşır, doğru. Ama diyelim ki dil bir sabit sağlıyor String.Empty, karşılaştığınız x = ""zaman niyet hakkında tam olarak böyle bir sabit yokmuş gibi biliyorsunuz. Boş bir dizenin intendetin olduğu dünya Java kodundaki tüm yerlerin, ""bahsettiğiniz bilgi kazanımını elde etmek için kullanmadığını garanti etmeniz gerekir . İronik olarak, C # bir sabit kullanıyor ve kullanımını teşvik ediyor, bu yüzden dediğim gibi, bunun çok tartışmalı bir tartışma olduğunu biliyorum.
chiccodoro

@chiccodoro - Evet, bu doğru. Bu nedenle, boş dize hazır bilgisi "", kazaları ekarte etmek için yasadışı olmalıdır. Şaka yapıyorum!
Jeffrey L Whitledge


3

Ben her zaman String "" yazarken, String havuzunda aynı String nesnesine başvurduğunu biliyorum.
Böyle bir garanti yok. Ve uygulamanızda buna güvenemezsiniz, karar vermek tamamen jvm'ye kalmış.

ya da dil yaratıcıları görüşlerimi paylaşmadılar mı?
Evet. Bana göre, çok düşük öncelikli bir şey gibi görünüyor.


6
Böyle bir garanti verilmez ... JLS durumun böyle olması gerektiğini söylüyor.
Tim Stone

@Tim 'Stajyer' çağrısı yapmadığınız sürece hayır. Programlı olarak iki eşit büyük dizeyi oluşturmak ve kontrol etmek kolaydır.
Nikita Rybak

@Zaman Örneğin, a + = "a" ifadesini tekrarlayın ; 100 kez b ile kontrol edin ve kontrol edin.
Nikita Rybak

5
Haklısınız, ancak tanımladığınız şey bir dizgi değişmezi veya sonucu derleme sırasında garanti edilebilecek bir ifade (örneğin String username = "Bob" + " " + "Smith";) değildir. Belirttiğiniz intern()gibi açıkça aramadığınız sürece, programlı olarak oluşturulan dizelerin stajyer olma garantisi yoktur . OP'nin senaryosu "", kod boyunca boş dize değişmezinin kullanılmasını açıklar ; bu, otomatik stajyerin gerçekleşeceği bir durumdur.
Tim Stone

@ Zaman String a = ""; for(int i = 0; i < 100; i++) {a += "a";} String b = ""; for(int i = 0; i < 100; i++) {b += "b";} a.intern(); b.intern();Şimdi ave bPermGen aynı bellek konumunu işaret. Bkz bu makalede
1ac0

1

Geç cevap, ama bence bu konuya yeni bir şeyler ekliyor.

Önceki cevapların hiçbiri orijinal soruyu cevaplamadı. Bazıları bir sabitin eksikliğini haklı çıkarmaya çalışırken, diğerleri sabitin eksikliğiyle başa çıkabilmenin yollarını gösterdi. Ancak hiç kimse sabitin yararı için zorlayıcı bir gerekçe sunmadı, bu yüzden eksikliği hala doğru bir şekilde açıklanmadı.

Bir sabit, bazı kod hatalarının fark edilmemesini önleyeceği için yararlı olacaktır.

"" İçin yüzlerce referans içeren geniş bir kod tabanınız olduğunu varsayalım. Birisi kodu kaydırırken bunlardan birini değiştirir ve "" olarak değiştirir. Böyle bir değişikliğin üretime fark edilmeme olasılığı yüksektir, bu noktada kaynağı tespit etmek zor olacak bir soruna neden olabilir.

Aynı hataya maruz kalırsa EMPTY adında bir kütüphane sabiti olan OTOH, EM PTY gibi bir şey için derleyici hatası oluşturur.

Kendi sabitinizi tanımlamak hala daha iyidir. Birisi hala başlatmayı yanlışlıkla değiştirebilir, ancak geniş kullanımı nedeniyle, böyle bir hatanın etkisinin fark edilmemesi, tek kullanımlık bir durumdaki bir hatadan çok daha zor olacaktır.

Bu, değişmez değerler yerine sabitleri kullanmanın genel avantajlarından biridir. İnsanlar genellikle düzinelerce yerde kullanılan bir değer için sabit kullanmanın, bu değeri tek bir yerde kolayca güncellemenizi sağladığını kabul eder. Daha az sıklıkla kabul edilen şey, bunun aynı zamanda değerin yanlışlıkla değiştirilmesini de engellemesidir, çünkü böyle bir değişiklik her yerde gösterilecektir. Yani, evet, "" EMPTY'den daha kısa, ancak EMPTY'nin kullanımı "" 'dan daha güvenlidir.

Dolayısıyla, orijinal soruya geri dönersek, sadece dil tasarımcılarının muhtemelen sık kullanılan değişmez değerler için sabitler sağlama avantajının farkında olmadıklarını tahmin edebiliriz. Umarım, bir gün Java'ya dize sabitleri eklenir.


-16

İddia edenler için ""ve String.Emptybirbirleriyle değiştirilebilir ya da ""daha iyidir, çok yanlış.

Her seferinde myVariable = "" gibi bir şey yaptığınızda; bir nesnenin örneğini oluşturuyorsunuz. Java'nın String nesnesinin bir EMPTY genel sabiti varsa, "" nesnesinin yalnızca 1 örneği olurdu

Örneğin: -

String.EMPTY = ""; //Simply demonstrating. I realize this is invalid syntax

myVar0 = String.EMPTY;
myVar1 = String.EMPTY;
myVar2 = String.EMPTY;
myVar3 = String.EMPTY;
myVar4 = String.EMPTY;
myVar5 = String.EMPTY;
myVar6 = String.EMPTY;
myVar7 = String.EMPTY;
myVar8 = String.EMPTY;
myVar9 = String.EMPTY;

10 (String.EMPTY dahil 11) 1 nesneye işaret

Veya: -

myVar0 = "";
myVar1 = "";
myVar2 = "";
myVar3 = "";
myVar4 = "";
myVar5 = "";
myVar6 = "";
myVar7 = "";
myVar8 = "";
myVar9 = "";

10 nesneden 10 nesneye

Bu verimsizdir ve büyük bir uygulama boyunca önemli olabilir.

Belki de Java derleyici veya çalışma zamanı tüm "" örneklerini aynı örneğe otomatik olarak gösterecek kadar etkilidir, ancak bu belirlemeyi yapmak için ek işlem yapmayabilir ve bu işlemi gerçekleştirebilir.


9
Yanlış, stackoverflow.com/questions/1881922/… 'a göre , "" dizesi String havuzundan yeniden kullanılacak.
RealHowTo

1
Ben aynı nesneyi yeniden kullanabilirsiniz ve eğer öyleyse, (dize havuzunda) bu nesneyi bulmak gerekiyor, çünkü hala daha az verimli olduğunu ifade, bu yüzden nasıl yanılıyorum? Ne olursa olsun, myVar = "" gibi hataları önlemek de dahil olmak üzere String.Empty'nin üstün olmasının birkaç nedeni vardır; ve daha önce belirttiğim performans iyileştirmesinin yanı sıra okunabilirlik. Başka bir nedenden dolayı dizgi değişmezleri oluşturmak yerine sabitleri kullanmak iyi bir uygulamadır; kodun bakımı daha kolaydır.
Antony Booth

1
Performans argümanınızın geçerli olduğundan şüpheliyim çünkü JLS, bir sabitin derleme zamanında değişmez olarak ele alınacağını söylüyor ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10. 5 ). Okunabilirlik daha iyi bir argüman.
RealHowTo

3
@AntonySmith - Sanırım Java'yı biraz daha fazla incelemeniz gerekiyor ya da şimdiye kadar hatanızı biliyorsunuzdur. Java dizeleri değişmez ve havuzdadır. Bu nedenle, kodda kaç kez bulunursa bulunsun, bir JVM'de "" için yalnızca ONE String nesnesi vardır. Bir dizenin boş olup olmadığını kontrol edebilirsinizif (text == "")
Ajoy Bhatia

2
Yanlış. Bu yorum silinmelidir.
Elad Tabak
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.