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?
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.
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.
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:
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.
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.
assert()
if (obj != null){}'den daha iyi değil, daha az gürültü kullanın.
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.
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
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
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:
nullparametresine izin veren veya
nulldeğ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
nullkabul 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.)
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.
Null ile ilgili aşağıdaki genel kurallar şu ana kadar bana çok yardımcı oldu:
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.
Null, veri modeliniz için uygun değerler alanındaysa, uygun şekilde ilgilenin.
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.
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
İş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.
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.
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.
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.
İ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.
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.
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 :)