Java'da ilkel vs sınıfı ne zaman kullanılır?


54

Java’nın Boolean (sınıf) ve boolean (ilkel) olduğunu görüyorum. Aynı şekilde, int (ilkel) vs bir Tamsayı (sınıf) var. Sınıf vs ilkel sürümünü ne zaman kullanacağınız konusunda en iyi uygulama nedir? Olmaması için belirli bir (performans?) Nedenim olmadığı sürece temelde sınıf sürümünü kullanmalı mıyım? Her birini kullanmanın en yaygın, kabul edilen yolu nedir?



Aklıma göre bunlar sınıf değil, kutu. Onlar sadece oradadır, bu nedenle nesnelerin gerekli olduğu ilkeleri, yani koleksiyonlarda kullanabilirsiniz. İki Tamsayıcı ekleyemezsiniz (taklit edebilirsiniz, ancak gerçekten java otomatik boks | sizin için değerlerin kutusudur).
stonemetal

Yanıtlar:


47

Etkili Java'nın 5. Maddesinde Joshua Bloch şöyle diyor:

Ders açıktır: ilkelleri kutulu ilkellere tercih et ve istemeden otomatik kutulamaya dikkat et .

Sınıflar için iyi bir kullanım, bunları genel türler olarak kullanırken (listeler ve haritalar gibi Koleksiyon sınıfları dahil) veya bunları örtük döküm yapmadan başka türlere dönüştürmek istediğinizde (örneğin Integersınıfın yöntemleri vardır doubleValue()veya olabilir) byteValue().

Düzenleme: Joshua Bloch'un nedeni:

// Hideously slow program! Can you spot the object creation?
public static void main(String[] args) {
    Long sum = 0L;
    for (long i = 0; i < Integer.MAX_VALUE; i++) {
         sum += i;
    }
    System.out.println(sum);
}

Bu program doğru cevabı alır, ancak bir karakterlik yazım hatası nedeniyle olması gerekenden çok daha yavaştır. Değişken yerine a sumolarak bildirilir , bu da programın yaklaşık 2 ^ 31 gereksiz örnek oluşturduğu anlamına gelir (kabaca her eklendiğinde bir tane ). Dan toplamının beyanı değiştirilmesi için 43 saniyeden benim makinede 6.8 saniyeye çalışma zamanını azaltır.LonglongLonglong iLong sumLonglong


2
Bloch'un sebeplerini sıraladıysanız, sonuçtan alıntı yapmak yerine, yardım eder!
vaughandroid

@Baqueta Gönderiyi düzenledim. Sebep performans.
m3th0dman,

Bu biraz daha net, teşekkürler. Şimdi kendi cevabımı gönderirken haklı hissediyorum. :)
vaughandroid

Lmax mimarisini ilgi çekici bulabilirsin - "Başka bir büyüklük sırasını yükseltmek biraz daha akıllıca geçti. LMAX ekibinin oraya ulaşmada yardımcı olacağı bazı şeyler vardı. önbellek dostu ve çöp konusunda dikkatli olun. Bunun bir örneği, özel olarak yazılmış bir dizi destekli Harita uygulamasına sahip, hasaf şifresi olan ilkel java'ları kullanmaktır . "


28

Standart uygulama, jeneriklerle ilgilenmediğiniz sürece, ilkellerle gitmektir ( otomatik kutulama ve kutudan çıkarma işleminin farkında olduğunuzdan emin olun !).

Sözleşmeyi takip etmek için bir takım iyi sebepler var:

1. Basit hatalardan kaçınırsınız:

Yeni başlayanları yakalayan bazı ince, sezgisel olmayan durumlar vardır. Tecrübeli kodlayıcılar bile bazen hata yapar ve bu hataları yaparlar (umarım bunu kodun hatalarını bulup hatayı bulduklarında küfür izlerler!).

En yaygın hata a == byerine kullanmaktır a.equals(b). İnsanlar a == bilkellerle çalışmaya alışkındır, bu nedenle Object sarmalayıcılarını kullanırken kolayca yapılabilir.

Integer a = new Integer(2);
Integer b = new Integer(2);
if (a == b) { // Should be a.equals(b)
    // This never gets executed.
}
Integer c = Integer.valueOf(2);
Integer d = Integer.valueOf(2);
if (c == d) { // Should be a.equals(b), but happens to work with these particular values!
    // This will get executed
}
Integer e = 1000;
Integer f = 1000;
if (e == f) { // Should be a.equals(b)
    // Whether this gets executed depends on which compiler you use!
}

2. Okunabilirlik:

Aşağıdaki iki örneği ele alalım. Çoğu insan ikincisinin daha okunaklı olduğunu söylerdi.

Integer a = 2;
Integer b = 2;
if (!a.equals(b)) {
    // ...
}
int c = 2;
int d = 2;
if (c != d) {
    // ...
}

3. Performans:

Aslında öyle olduğunu sadece temel öğeler kullanmaktan daha öncülleri için Nesne sarmalayıcılarını kullanmak daha yavaş. Nesne somutlaştırmanın maliyetini, yöntem çağrılarını vb. Her yerde kullandığınız şeylere ekliyorsunuz .

Knuth'un "... zamanın yaklaşık% 97'sini söyle: erken optimizasyon tüm kötülüklerin köküdür" alıntı gerçekten de geçerli değil. Kodu (veya sistemi) daha karmaşık hale getiren optimizasyonlardan bahsediyordu - eğer 2. maddeyi kabul ederseniz, bu kodu daha az karmaşık hale getiren bir optimizasyondur !

4. Kongre:

Dışarıdaki diğer Java programcılarının% 99'una farklı stilistik seçimler yaparsanız, 2 dezavantajı vardır:

  • Başkalarının kodunu okumayı zorlaştırırsın. Örneklerin / öğreticilerin / vb. Yerlerin% 99'u ilkelleri kullanacaktır. Ne zaman bir tane okursanız, alışkın olduğunuz tarzda nasıl görüneceğini düşünmek için ekstra bilişsel ek yükünüz olur.
  • Diğer insanlar kodunuzu okumayı zorlaştırır. Yığın Taşması ile ilgili soru sorduğunuzda, “neden ilkel kullanmıyorsunuz?” Sorusunu sorarak cevapları / yorumları gözden geçirmelisiniz. Bana inanmıyorsan, insanların parantez yerleştirme gibi şeylerle ilgili savaşlarına bak, bu da üretilen kodu etkilemiyor!

Normalde bazı puanları listelerdim ama dürüst olmak gerekirse, burada kongreye katılmamak için hiçbir iyi sebep düşünemiyorum!


2
İnsanları nesneleri karşılaştırmaya zorlama ==. Nesneler ile karşılaştırılmalıdır equals().
Tulains Córdova

2
@ user61852 Bunu yapacak bir şey olarak değil, yapılan ortak bir hata olarak önermiştim! Daha net yapmalı mıyım?
vaughandroid

Evet, nesnelerin karşılaştırılması gerektiğinden bahsetmiyorsunuz equals()... onlara geçici bir çözüm veriyorsunuz, böylece nesneleri karşılaştırırken ==beklenen sonuçları veriyorsunuz .
Tulains Córdova

İyi bir nokta. Değiştirdi.
vaughandroid

equals()İkinci kod pasajına ekledim ve oyumu değiştirdim.
Tulains Córdova

12

Genellikle ilkellerle giderim. Bununla birlikte bu sınıfları kullanarak bir özelliği Integerve Booleanatama olasılığıdır nulldeğişkenlerle. Tabii ki, bu, nullher zaman kontroller yapmanız gerektiği , ancak NullPointerException almak için yine de doğru başlatılmayan bazı intya da booleandeğişkenlerin kullanılması nedeniyle mantıksal hatalara sahip olmaktan daha iyi olduğu anlamına gelir .

Tabii ki, Java 8'den bu yana bir adım daha ileri gidebilirsiniz (ve muhtemelen gitmeli) ve örneğin bir değeri olan veya olmayan değişkenler için Integerkullanabilirsiniz Optional<Integer>.

Ek olarak, nullbu değişkenlere " bilinmeyen " veya " joker " bir değer atamak için kullanma imkanı sunar . Bu, bazı durumlarda, örneğin Üçlü Mantık'ta kullanışlı olabilir . Veya belirli bir nesnenin bazı şablonlarla eşleşip eşleşmediğini kontrol etmek isteyebilirsiniz; Bu durumda null, şablondaki nesnede herhangi bir değeri olabilecek değişkenler için kullanabilirsiniz .


2
(Olumsuz oy değildi, ama ...) Java, başlatılmamış değişkenleri zaten algılıyor ve kullanımına giden her kod yolunda kesinlikle bir değer atamasına kadar bir değişkeni okumanıza izin vermeyecek. Bu yüzden nullvarsayılan olarak atama yeteneğinden fazla bir şey elde edemezsiniz . Aksine: Değişkeni "başlatmamak" konusunda daha iyi olursunuz. Herhangi bir varsayılan değerin ayarlanması bile nullderleyiciyi kapatır ... ama aynı zamanda tüm kod yolları boyunca yararlı atama eksikliğini tespit etmekten de kaçınır. Böylece, derleyicinin yakalayabileceği bir hata çalışma zamanına kayar.
cHao

@cHao Peki ya değişkeni başlatmak için makul bir varsayılan değer yoksa ? Bunu 0.0, veya -1, veya Integer.MAX_VALUE, veya olarak ayarlayabilirsiniz False, ancak sonunda, varsayılan değer mi, yoksa bu değişkene atanmış gerçek bir değer mi olduğunu bilmiyorsunuz. Bunun önemli olduğu durumlarda, bir nulldeğere sahip olmak daha net olabilir.
tobias_k

Net değil, derleyiciye bir hata yayılana kadar sizi belirsiz bir mantık hakkında uyarmamasını söylemek daha kolay. : P Mantıklı bir varsayılanın olmadığı durumlarda , değişkeni başlatmayın. Sadece oraya koymak için makul bir değere sahip olduğunuzda ayarlayın. Bu , değerinizin doğru şekilde ayarlanmamış olması durumunda Java'nın derleme zamanında sizi durdurmasını sağlar .
cHao

Demek @cHao, orada durumlar olabilir olamaz değişkeni başlatmak ve gereken çalışma zamanında onunla başa. Bu gibi durumlarda, açıkça varsayılan olarak tanımlanabilen veya "sterilize edilmemiş" olarak tanımlanabilen "boş" gibi bir "varsayılan", aynı zamanda geçerli bir değer olabilecek herhangi bir derleme zamanı başlatmasından daha iyi olabilir.
tobias_k

Aklında böyle bir durum var mı? Düşünebildiğim durumlar arayüz sınırlarında (örneğin: parametre veya geri dönüş tipleri olarak) ... ama orada bile olsa sarılırlarsa çok daha iyi olurdu. (Çıplaklar null, boş paranoya da dahil olmak üzere bir dizi sorunla gelirler.) Bir işlev içerisinde, kullanım noktasında gerçekte başlatılamayan bir değişken, tipik olarak ele geçen durumları gösterir. (Kesin atama analizi çok basittir, bu yüzden yanlış pozitifler mümkündür. Fakat bunları mantığı basitleştirerek sık sık çözebilirsiniz.)
cHao

2

Layman'ın sözleriyle:

Koleksiyonlara bir şeyler eklemeniz gerektiğinde sarmalayıcıları kullanırsınız.

Koleksiyonlar ilkeli tutamaz.


0

Java, m3th0dman'ın işaret ettiği gibi otomatik kutulama özelliğine sahiptir. Mümkün olan en düşük seviyede düşünün ve otomatik kutulamanın (içeri veya dışarı) ilkel bir değerin, uygulamanızın yerel veri türleriyle çalışıyorsanız, ihtiyacınız olmayan bazı görevlerde harcanan saat döngüleri anlamına geldiğini göreceksiniz.

Genel bir kural olarak, mümkün olduğunda yerel veri türlerini kullanmaya çalışmalısınız.

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.