it-swarm-tr.com

Java'da null'ları ele almanın en iyi yolu?

NullPointerException nedeniyle başarısız bazı kod var. Nesnenin bulunmadığı nesnede bir yöntem çağrılıyor.

Ancak bu, bunu düzeltmenin en iyi yolu hakkında düşünmemi sağladı. Ben null işaretçi istisnalar için gelecekteki kanıt kodu böylece her zaman nulls için defansif kodlama, ya da null aşağı akış olmayacak şekilde null nedenini düzeltmek gerekir.

Düşüncelerin nelerdir?

21
Shaun F

Null yönteminiz için makul bir girdi parametresiyse, yöntemi düzeltin. Değilse, arayanı düzeltin. "Makul" esnek bir terimdir, bu yüzden aşağıdaki testi öneririm: Yöntem nasıl boş bir girdi içermelidir? Birden fazla olası cevap bulursanız, null değeri değil mantıklı bir girdidir.

45
user281377

null kullanmayın, İsteğe bağlı kullanın

Belirttiğiniz gibi, Java) içindeki null ile ilgili en büyük sorunlardan biri her yerde veya en azından kullanılabilir tüm referans türleri için.

Bunun null olabileceğini ve ne olamayacağını söylemek mümkün değil.

Java 8 çok daha iyi bir model sunar: Optional.

Oracle örneği:

String version = "UNKNOWN";
if(computer != null) {
  Soundcard soundcard = computer.getSoundcard();
  if(soundcard != null) {
    USB usb = soundcard.getUSB();
    if(usb != null) {
      version = usb.getVersion();
    }
  }
}

Bunların her biri başarılı bir değer döndürüp getirmeyebilirse, API'ları Optionals olarak değiştirebilirsiniz:

String name = computer.flatMap(Computer::getSoundcard)
    .flatMap(Soundcard::getUSB)
    .map(USB::getVersion)
    .orElse("UNKNOWN");

Türdeki seçenekliği açıkça kodlayarak, arayüzleriniz çok daha iyi olacak ve kodunuz daha temiz olacaktır.

Java 8 kullanmıyorsanız, com.google.common.base.Optional Google Guava'da.

Guava ekibi tarafından iyi bir açıklama: https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained

Null'a yönelik dezavantajların daha genel bir açıklaması ve çeşitli dillerden örnekler: https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/


@ Nonnull, @Nullable

Java 8, bu ek açıklamaları IDE'ler gibi kod kontrol araçlarının sorun yakalamasına yardımcı olmak için ekler. Etkinlikleri açısından oldukça sınırlıdırlar.


Ne zaman anlamlı olduğunu kontrol edin

Kod kontrolünüzün% 50'sini boş yazmayın, özellikle kodunuzun null değeriyle yapabileceği mantıklı bir şey yoksa.

Öte yandan, null kullanılabilirse ve bir şey ifade ediyorsa, onu kullandığınızdan emin olun.


Sonuçta, null'yi Java'dan kaldıramazsınız. Mümkün olduğunca Optional soyutlamasını değiştirmenizi ve null ile ilgili makul bir şey yapabileceğinizi kontrol etmenizi önemle tavsiye ederim.

21
Paul Draper

Bunu ele almanın birden fazla yolu vardır, kodunuzu if (obj != null) {} ile biberlemek ideal değildir, dağınıktır, bakım döngüsü sırasında daha sonra kodu okurken gürültü ekler ve unutulması kolaydır. Bu kazan plakası sarması yapmak için.

Kodun sessizce yürütülmeye devam etmesini isteyip istemediğinize bağlıdır. null bir hata mı yoksa beklenen bir durum mu?.

Boş olan nedir

Her tanım ve durumda, Null mutlak veri eksikliğini temsil eder. Veritabanlarındaki boş değerler, bu sütun için değer eksikliğini temsil eder. null String, boş bir String ile aynı değildir, null int teoride SIFIR ile aynı şey değildir. Pratikte "duruma bağlıdır". Boş String, String sınıfı için iyi bir Null Object Uygulaması yapabilir, Integer için iş mantığına bağlıdır.

Alternatifler:

  1. Null Object şablonu. Nesnenizin null durumunu temsil eden bir örneği oluşturun ve Null uygulamasına başvuruda bulunarak bu türe yapılan tüm başvuruları başlatın. Bu, null olabilecek ve geçerli bir durum olarak null olması beklenen diğer nesnelere çok fazla referansı olmayan basit değer türü nesneler için kullanışlıdır.

  2. Parametrelerin boş kalmasını önleyen bir Null Checker En-boy oranına sahip yöntemleri örmek için En Boy Odaklı araçları kullanın. Bu, null öğesinin hata olduğu durumlar içindir.

  3. assert()if (obj != null){}'den daha iyi değil, daha az gürültü kullanın.

  4. Java İçin Sözleşmeler gibi bir Sözleşme Uygulama aracı kullanın. AspectJ gibi bir şeyle aynı kullanım durumu, ancak daha yeni ve harici yapılandırma dosyaları yerine Ek Açıklamalar kullanıyor. Unsurların ve Eklemelerin her ikisinin de en iyisi.

1, gelen verilerin null olduğu bilindiğinde ideal bir çözümdür ve yukarı yönlü tüketicilerin tüm boş kontrol kazan plakası koduyla uğraşmasına gerek kalmayacak şekilde bazı varsayılan değerlerle değiştirilmesi gerekir. Bilinen varsayılan değerlere karşı kontrol etmek de daha etkileyici olacaktır.

2, 3 ve 4, NullPointerException yerine her zaman ve iyileştirici olan daha bilgilendirici bir şey koymak için uygun alternatif İstisna oluşturuculardır.

Sonunda

null = Java hemen hemen her durumda bir mantık hatasıdır. NullPointerExceptions 'ın kök nedenini her zaman ortadan kaldırmak için çaba göstermelisiniz. null koşullarını iş mantığı olarak oluşturur. if (x == null) { i = someDefault; } sadece varsayılan nesne örneğine ilk atamayı yapar.

8
user7519

Boş kontroller eklemek testi sorunlu hale getirir. Bu harika derse bakın ...

Google Tech görüşmeleri dersine göz atın: "Temiz Kod Görüşmeleri - Bir Şeyleri Arama!" 24 dakika hakkında konuşuyor

http://www.youtube.com/watch?v=RlfLCWKxHJ0&list=PL693EFD059797C21E

Paranoyak programlama, her yerde boş kontroller eklemeyi içerir. İlk başta iyi bir fikir gibi görünüyor, ancak test açısından bakıldığında, null çek tipi testinizle başa çıkmayı zorlaştırıyor.

Ayrıca, bazı nesnelerin varlığı için bir önkoşul oluşturduğunuzda,

class House(Door door){

    .. null check here and throw exception if Door is NULL
    this.door = door
}

bir istisna atacağınız için House yaratmanızı engeller. Test durumlarınızın Door'dan başka bir şeyi test etmek için sahte nesneler oluşturduğunu varsayın, kapı gerekli olduğundan bunu yapamazsınız

Mock oluşturma cehennemi ile acı çekenler bu tür rahatsızlıkların farkındadır.

Özetle, test takımınız Kapılar, Evler, Çatılar veya paranoyak olmak zorunda kalmadan test edilecek kadar sağlam olmalıdır. Seroiusly, testinizdeki belirli nesneler için bir boş kontrol testi eklemek ne kadar zor :)

Her zaman işe yarayan uygulamaları tercih etmelisiniz, çünkü HOPING yerine işe yaradığını kanıtlayan birkaç testiniz var, çünkü her yerde bir dizi ön koşullu null kontrolünüz var

8
Constantin

tl; dr - beklenmedik nulls olup olmadığını kontrol etmek İYİ ama bir uygulamanın onları iyi yapmaya çalışması için KÖTÜ.

Detaylar

Açıkçası, null'nin bir yönteme geçerli bir girdi veya çıktı olduğu ve diğerlerinin olmadığı bir durum vardır.

Kural # 1:

null parametresine izin veren veya null değeri döndüren bir yöntem için javadoc bunu açıkça belgelemeli ve açıklamalıdır null'in anlamı nedir.

Kural # 2:

API yöntemi, bunu yapmak için iyi bir neden olmadığı sürece null kabul veya iade olarak belirtilmemelidir.

Bir yöntemin nulls karşısındaki "sözleşmesinin" açık bir belirtimi göz önüne alındığında, bir yöntemin iletilmesi veya döndürülmesi bir programlama hatasıdır null yapmamanız gereken yer.

Kural # 3:

Bir uygulama "iyi" programlama hataları yapmaya çalışmamalıdır.

Bir yöntem, orada olmaması gereken bir null tespit ederse, sorunu başka bir şeye dönüştürerek düzeltmeye çalışmamalıdır. Bu sadece programcıdan sorunu gizler. Bunun yerine, NPE'nin gerçekleşmesine izin vermeli ve programlayıcının kök nedeninin ne olduğunu anlayabilmesi ve düzeltebilmesi için bir hataya neden olmalıdır. Umarım test sırasında hata fark edilir. Değilse, bu test metodolojiniz hakkında bir şeyler söylüyor.

Kural # 4:

Mümkünse, programlama hatalarını erken tespit etmek için kodunuzu yazın.

Kodunuzda çok sayıda NPE ile sonuçlanan hatalar varsa, en zor şey null değerlerinin nereden geldiğini bulmak olabilir. Teşhisi kolaylaştırmanın bir yolu, kodunuzu yazmaktır, böylece null en kısa sürede algılanır. Genellikle bunu diğer kontrollerle birlikte yapabilirsiniz; Örneğin.

public setName(String name) {
    // This also detects `null` as an (intended) side-effect
    if (name.length() == 0) {
        throw new IllegalArgumentException("empty name");
    }
}

(Açıkça 3. ve 4. kuralların gerçeğe uygun hale getirilmesi gereken durumlar vardır. Örneğin (kural 3), bazı uygulamalar sonra devam etmeyi denemelidir Muhtemelen programlama hatalarını tespit etmek. Ve (kural 4) hatalı parametrelerin çok fazla kontrol edilmesinin performans etkisi olabilir.)

4
Stephen C

Yöntemin savunma amaçlı olarak düzeltilmesini öneriyorum. Örneğin:

String go(String s){  
    return s.toString();  
}

Bunun çizgileri boyunca daha fazla olmalı:

String go(String s){  
    if(s == null){  
       return "";  
    }     
    return s.toString();  
}

Bunun kesinlikle önemsiz olduğunu anlıyorum, ancak invoker bir nesne beklerse, onlara bir null iletilmesine neden olmayacak varsayılan bir nesne verin.

3
Woot4Moo

Null ile ilgili aşağıdaki genel kurallar şu ana kadar bana çok yardımcı oldu:

  1. Veriler denetiminizin dışından geliyorsa, sistematik olarak null olup olmadığını kontrol edin ve uygun şekilde hareket edin. Bu, işleve mantıklı bir istisna atmak anlamına gelir (işaretlenmiş veya işaretlenmemiş, sadece istisnanın adının tam olarak neler olduğunu söylediğinden emin olun). Ancak ASLA sisteminizde potansiyel olarak sürprizler taşıyabilecek bir değer bırakmayın.

  2. Null, veri modeliniz için uygun değerler alanındaysa, uygun şekilde ilgilenin.

  3. Değerleri döndürürken mümkün olduğunca boş değer döndürmemeye çalışın. Her zaman Boş listeler, boş dizeler, Boş Nesne kalıpları tercih edin. Belirli bir kullanım durumu için verilerin mümkün olan en iyi gösterimi olduğunda null değerlerini döndürülen değerler olarak saklayın.

  4. Muhtemelen en önemlisi ... Testler, testler ve tekrar test. Kodunuzu test ederken bir kodlayıcı olarak test etmeyin, bir Nazi psikopat dominatrix olarak test edin ve bu koddan cehenneme işkence etmenin her türlü yolunu hayal etmeye çalışın.

Bu, paranoyak tarafta, sistemleri dış dünyaya bağlayan cephelere ve proxy'lere ve bol miktarda fazlalık ile içeride sıkı bir şekilde kontrol edilen değerlere yol açan null'lara göre biraz eğilimlidir. Buradaki dış dünya, kendimi kodlamadığım hemen hemen her şey anlamına geliyor. Bir maliyet çalışma süresi taşıyor ama şimdiye kadar nadiren kod "boş güvenli bölümleri" oluşturarak bunu optimize etmek zorunda kaldı. Yine de sağlık için uzun süredir çalışan sistemler oluşturduğumu söylemeliyim ve son istediğim, beklenmedik bir boş gösterici nedeniyle iyot alerjilerinizi CT tarayıcı çökmelerine taşıyan arabirim alt sistemi, çünkü başka bir sistemdeki bir başkası isimlerin kesme işaretleri veya 但 耒耨。 gibi karakterler içerir

neyse .... benim 2 sent

2
Newtopian

İşlevsel dillerden Option/Some/None desenini kullanmayı öneriyorum. Ben bir Java uzmanı değilim, ama C # projemde bu kalıbın kendi uygulamasını yoğun bir şekilde kullanıyorum ve Java dünya.

Bu modelin arkasındaki fikir şudur: Bir değerin kaybolması olasılığı olduğunda durumun mantıklı olması (örneğin, veritabanından kimliğe göre geri çekilirken), T'nin olası bir değer olduğu Option [T] türünde bir nesne sağlarsınız. . Ben [T] sınıfında bir değer nesnesinin olmaması durumunda, değeri içeren Bazı [T] 'nin değer - nesnesinin varlığı geri döndüğünde.

Bu durumda, değer yokluğu olasılığını ele almalısınız ve kod incelemesi yaparsanız yanlış işleme placecini kolayca bulabilirsiniz. C # dil uygulamasından ilham almak için bitbucket veri havuzuma bakın https://bitbucket.org/mikegirkin/optionsomenone

Boş bir değer döndürürseniz ve mantıksal olarak bir hataya eşdeğerse (örneğin dosya yoksa veya bağlanamadığınızda) bir istisna atmanız veya başka bir hata işleme deseni kullanmanız gerekir. Bunun arkasındaki fikir, yine, değer yokluğu durumunu ele almanız gerektiğinde ve yanlış kullanım yerlerini kolayca bulabileceğiniz bir çözümle sonuçlanır. kodda.

1
Hedin
  1. Gerçekten isteğe bağlı olmadığı sürece, isteğe bağlı türü kullanmayın, düzenli olarak buggy kodu yazdığınız için değil, bir seçenek olarak gerçekten null beklemediyseniz, çıkış genellikle bir istisna olarak daha iyi işlenir.

  2. Google'ın makalesinde belirtildiği gibi, sorunu kullandığı bir tür olarak null değil. Sorun şu ki, boş değerler kontrol edilmeli ve ele alınmalıdır, genellikle zarif bir şekilde çıkılabilirler.

  3. Programın rutin çalışması dışındaki alanlarda geçersiz koşulları temsil eden bir dizi boş durum vardır (geçersiz kullanıcı girişi, veritabanı sorunları, ağ hatası, eksik dosyalar, bozuk veriler); sadece oturum açmak için.

  4. İstisna işlemeye, isteğe bağlı gibi işleyicinin belleğe öncelikli tembel yüklemesi için erken destek de dahil olmak üzere ortaya çıkmalarının olağanüstü doğası için anlamlı olan bir türden farklı olarak JVM'de farklı operasyonel önceliklere ve ayrıcalıklara izin verilir. her zaman etrafında asılı gerekir.

  5. Her yerde null işleyiciler yazmanıza gerek yoktur, yalnızca gerçekleşme olasılığı yüksek olan yerlerde, potansiyel olarak güvenilir olmayan veri hizmetine eriştiğiniz her yerde ve bunların çoğu kolayca soyutlanabilecek birkaç genel kalıba düştüğü için nadir durumlar dışında bir işleyici çağrısı.

Bu yüzden cevabım kontrol edilen bir istisnaya sarın ve ele alalım ya da yetenekleriniz dahilindeyse güvenilir olmayan kodu düzeltirim.

0
J-Boss

Yönteminizin olası sonuçlarından biri null değerse, bunun için defansif olarak kodlamanız gerekir, ancak bir yöntemin null olmayan bir değer döndürmesi gerekiyorsa, ancak bunu kesin olarak düzeltmezdim.

Her zamanki gibi, hayatta çoğu şeyde olduğu gibi, duruma bağlıdır :)

0
jonezy

Apache Commons ' lang kütüphaneler boş değerleri işlemek için bir yol sağlar

sınıftaki defaultIfNull yöntemi ObjectUtils geçirilen nesne null ise varsayılan bir değer döndürmenizi sağlar

0
Mahmoud Hossam