Null parametresi için IllegalArgumentException veya NullPointerException? [kapalı]


547

Bir özellik için basit bir ayarlayıcı yöntemi var ve nullbu özel özellik için uygun değil. Bu durumda her zaman yırtıldım: Bir IllegalArgumentExceptionveya bir NullPointerException? Javadoclardan her ikisi de uygun görünüyor. Bir tür anlaşılmış standart var mı? Yoksa bu, tercih ettiğiniz her şeyi yapmanız gereken şeylerden sadece biri mi ve ikisi de gerçekten doğru mu?

Yanıtlar:


299

Bir gibi görünüyor IllegalArgumentExceptionEğer istemiyorsanız çağrılır nullizin verilen bir değer olması ve NullPointerExceptionsen çalışıyormuş atılmış olacaktır kullanmak dışarı dönüşler olmaya olduğu bir değişken null.


33
Bu soruya verilen aşağıdaki yanıtlar, NullPointerException'ın doğru istisna olduğu konusunda ikna edici argümanlar yapar: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; ve stackoverflow.com/a/6358/372926 .
SamStephens

2
IllegalArgumentExceptionJava ile çelişmektedir Objects.requireNonNull (T) ve Guava en Preconditions.checkNotNull (T) bir atar NullPointerException. Bununla birlikte, doğru cevap Jason Cohen'in mükemmel cevabı ve yorum bölümündeIllegalArgumentException açıklandığı gibi kesin .
matoni

417

Aşağıdaki nedenlerle (NPE) IllegalArgumentExceptiondeğil (IAE) kullanmalısınız NullPointerException:

İlk olarak NPE JavaDoc , NPE'nin uygun olduğu durumları açıkça listeler. Hepsi atılır olduğunu Bildirimi çalışma zamanı tarafından zaman nulluygunsuz kullanılır. Buna karşılık, IAE JavaDoc daha net olamazdı: "Bir yöntemin yasadışı veya uygunsuz bir argümandan geçirildiğini belirtmek için atıldı." Evet, bu sensin!

İkincisi, yığın izlemede bir NPE gördüğünüzde, ne varsayıyorsunuz? Muhtemelen birisinin kaydı silindi null. IAE'yi gördüğünüzde, yığının en üstündeki yöntemin arayanının geçersiz bir değerde geçtiğini varsayarsınız. Yine, ikinci varsayım doğrudur, birincisi yanıltıcıdır.

Üçüncüsü, IAE parametreleri doğrulamak için açıkça tasarlandığından, bunu varsayılan istisna seçimi olarak kabul etmeniz gerekir, o zaman neden NPE'yi seçesiniz? Kesinlikle farklı davranışlar için değil - gerçekten arama kodunun NPE'leri IAE'den ayrı yakalamasını ve sonuç olarak farklı bir şey yapmasını bekler misiniz? Daha spesifik bir hata mesajı iletmeye mi çalışıyorsunuz? Ancak bunu, tüm diğer yanlış parametreler için yapmanız gerektiği gibi, istisna mesajı metninde yapabilirsiniz.

Dördüncüsü, diğer tüm yanlış parametre verileri IAE olacaktır, neden tutarlı olmuyorsunuz? Neden bir yasadışı nullbu kadar özeldir ki diğer tüm yasadışı argümanlardan ayrı bir istisnayı hak eder?

Son olarak, Java API'nin bazı bölümlerinin NPE'yi bu şekilde kullandığı diğer cevaplar tarafından verilen argümanı kabul ediyorum. Bununla birlikte, Java API, istisna türlerinden adlandırma kurallarına kadar her şeyle tutarsızdır, bu yüzden Java API'sini (en sevdiğiniz kısmı) körü körüne kopyalamak, bu diğer hususları ortadan kaldırmak için yeterince iyi bir argüman olmadığını düşünüyorum.


119
Etkili Java 2nd Edition, Madde 60: "Muhtemelen, tüm hatalı yöntem çağrıları yasadışı bir argümana veya yasadışı duruma kaybolur, ancak bazı istisnalar belirli türdeki yasadışı argümanlar ve durumlar için standart olarak kullanılır. null değerleri yasaklanmışsa, kural IllegalArgumentException yerine NullPointerException özelliğinin atılmasını gerektirir. Benzer şekilde, bir arayanın bir dizini temsil eden bir parametrede bir dizinin aralık dışında bir değerini geçirmesi durumunda IndexOutOfBoundsException öğesi bir diziye atılır. "
Gili

33
NPE için JavaDoc ayrıca şunları da belirtir: "Uygulamalar, bu nesnenin null nesnesinin diğer yasadışı kullanımlarını belirtmek için örnekleri atmalıdır." Bu daha açık olabilir :(
R. Martinho Fernandes

12
Ne yazık ki, doğrulama yöntemleri Validate.notNull(ortak dil) ve Preconditions.checkNotNull(guava) her ikisi de NPE atar :-(
Aaron Digulla


16
@AaronDigulla, Guava dokümanlarından: "IAE'yi boş bir argümana atmak lehine birçok geçerli argüman olduğunu biliyoruz. Aslında, 15 yıldan daha eski bir zaman makinemiz olsaydı, Bununla birlikte, JDK ve NullPointerException'ın Etkili Java tercihine sadık kalmaya karar verdik.AEE'nin doğru olduğuna inanıyorsanız, hâlâ checkArgument(arg != null)argümanı döndürmeden rahatça kullanabilirsiniz, ya da projenize yerel bir yardımcı program. " code.google.com/p/guava-libraries/wiki/IdeaGraveyard
Arto Bendiken

162

Standart atmaktır NullPointerException. Genel olarak yanılmaz "Etkili Java", bunu Madde 42 (birinci baskı), Madde 60 (ikinci baskı) veya Madde 72 (üçüncü baskı) "Standart istisnaların kullanılmasını destekleyin" bölümünde kısaca tartışır:

"Muhtemelen, tüm hatalı yöntem çağrıları yasadışı bir argümana veya yasadışı duruma kaynar, ancak diğer istisnalar standart olarak belirli türdeki yasadışı argümanlar ve durumlar için kullanılır. Bir arayan, null değerlerin yasaklandığı bazı parametrelerde null değerini iletirse, konvansiyon IllegalArgumentException yerine NullPointerException oluşturuluyor. "


95
Kesinlikle katılmıyorum. NullPointerExceptions yalnızca JVM yanlışlıkla boş bir başvuru izliyorsa atılmalıdır. Sabah 3'teki koda bakmanızda size yardımcı olan fark budur.
Thorbjørn Ravn Andersen

26
Mutlaka standart ile aynı fikirde değilim (konuya her iki şekilde de gidebilirim), ancak JDK boyunca standart kullanımın ne olduğunu, dolayısıyla Etkili Java bunun için davayı yapıyor. Bence bu standardı takip edip etmemeyi veya doğru olduğunu düşündüğünüz şeyi yapmayı seçmektir. Çok iyi bir nedeniniz yoksa (ve bu kesinlikle hak kazanabiliyorsa), standart uygulamayı takip etmek en iyisidir.
GaryF

21
Kural dışı durum izlemesi kural dışı durumun noktasını gösterir, bu nedenle kural dışı durum türündeki fark sizin için cehenneme neden oluyorsa veya "size yardımcı olan fark" ise, çok yanlış bir şey yapıyorsunuz demektir.
Jim Balter

8
Fanteziler ve incelik. MB, "NullPointerException'a null olup olmadığını ve neden null olmaması gerektiğini söyleyen bir mesaj verebildiğiniz için sabit hata ayıklama hakkındaki argümanların sahte olduğunu unutmayın."
Jim Balter

10
Buradaki orijinal cevaplayıcı olarak, bunun o kadar önemli olmadığını söyleyeyim. Kesinlikle 6 yıllık bir konuşma gerektirmez. Hangisini seçerseniz seçin, tutarlı olun. Belirttiğim gibi standart NPE. Herhangi bir nedenle IAE'yi tercih ediyorsanız, bunun için gidin. Sadece tutarlı olun.
GaryF

138

Java 7'de yöntemi IllegalArgumentExceptionfark ettiğimde bugüne kadar null parametreleri atmaktan yanayım, java.util.Objects.requireNonNullbu yöntemle yapmak yerine:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

yapabilirsin:

Objects.requireNonNull(param);

ve geçtiğiniz NullPointerExceptionparametre ise bir atar null.

Bu yöntemin ortasında doğru patlama olduğu için java.util, varlığını atmanın NullPointerException"bir şeyler yapmanın Java yolu" olduğuna dair oldukça güçlü bir gösterge olarak kabul ediyorum .

Bence her şeye karar verdim.

Sabit hata ayıklama ile ilgili argümanların sahte olduğunu unutmayın, çünkü elbette NullPointerExceptionnull ve niçin null olmaması gerektiğini söyleyen bir mesaj verebilirsiniz . Aynen IllegalArgumentException.

Ek bir avantajı, NullPointerExceptionyüksek performanslı kritik kodda, null (ve NullPointerExceptionkolay bir hata mesajı ile) için açık bir denetimden vazgeçebilmeniz ve null üzerinde NullPointerExceptionbir yöntemi çağırdığınızda otomatik olarak alacağınıza güvenmenizdir. parametre. Bir yöntemi hızlı bir şekilde çağırmanız (yani hızlı bir şekilde başarısız olmanız) koşuluyla, geliştirici için kullanıcı dostu kadar değil, aynı etkiye sahip olursunuz. Çoğu zaman açıkça kontrol etmek ve hangi parametrenin null olduğunu belirtmek için yararlı bir mesaj atmak daha iyidir, ancak performansın yöntem / kurucunun yayınlanmış sözleşmesini bozmadan dikte etmesi durumunda değiştirme seçeneğine sahip olmak güzeldir.


14
Guava Preconditions.checkNotNull(arg)da NPE fırlatır.
assylias

14
Bu, geçersiz null ARGUMENTS için NullPointerException'a daha fazla ağırlık eklemiyor. Hem JDK requirNonNull () hem de Guava checkNotNull () kodun herhangi bir yerine, herhangi bir nesneyle çağrılabilir. Bunları örneğin bir döngü içinde çağırabilirsiniz. requirNotNull () ve checkNotNull () bazı yöntem bağımsız değişkenleriyle çağrıldığını ve IllegalArgumentException değerini atamadığını varsayamazdı. Guava'nın ayrıca IllegalArgumentException özel durumu oluşturan Preconditions.checkArgument () yöntemine sahip olduğunu unutmayın.
Bogdan Calmac

2
Bogdan tarafından adil bir nokta, ben requirNonNull tipik (ve genellikle amaçlanan) kullanımı şüpheli olsa da argüman kontrolü içindir. Bir şeyin bir döngüde boş olmadığını kontrol etmeniz gerekiyorsa, bir iddianın tipik bir yol olacağını düşünürdüm.
MB.

15
Object.requireNonNull () JavaDoc argümana ağırlık eklediğini düşünüyorum: "Bu yöntem öncelikle yöntemler ve yapıcılar parametre doğrulama yapmak için tasarlanmıştır"
Richard Zschech

Kapalı null denetimler lehine performans bağımsız değişkeninin genellikle geçersiz olduğunu unutmayın. JIT, kullanıcı null kontrollerini tanıyabilir ve aşağıdaki zımni null kontrolünü kullanabilir ve / veya her iki null kontrol türünde de aynı optimizasyon setini kullanabilir. Daha fazla bilgi için bu wiki'ye bakın , özellikle: Kullanıcı tarafından yazılan boş denetimler çoğu durumda JVM tarafından eklenenlerle işlevsel olarak aynıdır. Tabii ki, boş mesajlarınızda özel mesajlar gibi meraklı bir şey yapıyorsanız, bu optimizasyon geçerli olmayabilir.
BeeOnRope

70

JDK kütüphanelerinin tasarımını, özellikle Koleksiyonlar ve Eşzamanlılık'ı takip etme eğilimindeyim (Joshua Bloch, Doug Lea, bu adamlar katı API'lerin nasıl tasarlanacağını biliyorlar). Her neyse, JDK'daki birçok API proaktif olarak atar NullPointerException.

Örneğin, Map.containsKeydurumlar için Javadoc :

@throws Anahtar null ise ve bu harita null anahtarlara izin vermiyorsa NullPointerException (isteğe bağlı).

Kendi NPE'nizi atmak tamamen geçerlidir. Kural, kural dışı durum iletisinde null olan parametre adını eklemektir.

Desen gider:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

Ne yaparsanız yapın, başka bir kod kullanmaya çalıştığında kötü bir değerin ayarlanmasına ve daha sonra bir istisna atmasına izin vermeyin. Bu hata ayıklamayı kabus yapar. Her zaman "başarısız-hızlı" ilkesini izlemelisiniz.


3
Düşünce için yiyecek: Belki de NullPointerException'ın IllegalArgumentException öğesini genişletmemesinin nedeni, ilkinin yöntem bağımsız değişkenlerini içermeyen durumlarda ortaya çıkabilmesidir.
Gili

2
@Gili: Java bu sorunla karşılaşır, çünkü Java birden fazla kalıtımı desteklemez. Java MI'yı destekliyorsa, hem IllegalArgumentException hem de NullPointerException öğelerinden devralınan bir istisna atabilirsiniz.
Yalan Ryan

7
İletinin, her zaman null olacağı için argümanı içermemesi gerekir: "null null olmamalıdır", çok yararlı değil. :-) Aksi takdirde, katılıyorum, anlamlı bir mesajla "zengin" bir NPE yapabilirsiniz.
PhiLho

5
Kabul etmeliyim - şüphe duyduğunuzda standart API'yi takip edin. API'daki her şey sizin için ideal değildir, ancak yine de yüzlerce geliştirici tarafından korunur ve yinelenir ve milyonlarca programcı tarafından kullanılır. Şimdi Java 7'de bu şekilde kullanılan başka bir NPE örneğimiz var; Objects.requireNonNull (T obj) yöntemi - nesne başvurularının boş olmadığını kontrol etmek için açıkça belirtilir, yöntemler / yapıcılarda parametre doğrulaması yapmak için açıkça belirtilir ve nesne boşsa NPE atmak için açıkça belirtilir. Sonu
flamming_python

44

İyi sunulduğu için Jason Cohen'in iddiasını oyladı. Adım adım parçalayayım. ;-)

  • NPE javadoc açıkça diyor "boş nesnenin diğer yasa dışı kullanımları" . Çalışma zamanının olmaması gerektiğinde boş bir değerle karşılaştığı durumlarla sınırlıysa, tüm bu durumlar çok daha özlü bir şekilde tanımlanabilir.

  • Yanlış olanı varsayarsanız yardımcı olamazsınız, ancak kapsüllemenin düzgün bir şekilde uygulandığını varsayarsak, bir yöntemin uygun olmayan bir boş algılayıp bir istisna tetikleyip tetiklememesi gibi bir null değerinin uygun olmayan bir şekilde kaldırıldığına dikkat etmemeli veya fark etmemelisiniz.

  • Ben seçerdim NPE üzerinde IAE birden fazla nedenden dolayı

    • Yasadışı operasyonun doğası hakkında daha spesifik
    • Yanlışlıkla null değerlere izin veren mantık, yanlışlıkla yasadışı değerlere izin veren mantıktan çok farklı olma eğilimindedir. Örneğin, bir kullanıcı tarafından girilen verileri doğrularsam, kabul edilemez bir değer alırsam, bu hatanın kaynağı uygulamanın son kullanıcısıdır. Bir boş değer alırsam, bu programcı hatasıdır.
    • Geçersiz değerler yığın taşmaları, bellek yetersizliği hataları, ayrıştırma istisnaları vb. Gibi şeylere neden olabilir. Bu nedenle IAE'yi aslında RuntimeException altındaki tüm istisnaların EN GENELİ olarak görüyorum.
  • Aslında, diğer geçersiz argümanlar her türlü istisna ile sonuçlanabilir. UnknownHostException , FileNotFoundException , çeşitli sözdizimi hatası istisnaları, IndexOutOfBoundsException , kimlik doğrulama hataları vb.

Genel olarak, geleneksel olarak başarısız hızlı ilkesine uymayan kod ile ilişkili olduğu için NPE çok malign hissediyorum . Bu, ayrıca JDK'nın NPE'leri bir mesaj dizesi ile doldurmaması, gerçekten sağlam olmayan güçlü bir olumsuz duygu yarattı. Gerçekten de, NPE ve IAE arasındaki çalışma zamanı perspektifinden fark kesinlikle isimdir. Bu açıdan, isimle ne kadar kesin olursanız, arayan kişiye o kadar netlik verirsiniz.


Çoğu denetlenmeyen istisna arasındaki fark sadece addır.
Thorbjørn Ravn Andersen

20

Bu "Kutsal Savaş" tarzı bir soru. Diğer bir deyişle, her iki alternatif de iyidir, ancak insanlar ölüme karşı savunacakları tercihlerine sahip olacaklar.


Hayır, bu sorunun sadece bir doğru yanıtı vardır ve yönteme girdi yanlış olduğunda throw IllegalArgument istisnasını kullanmaktır. Ayrıca geliştirici ortamında, giriş geçerliliğini kontrol etmek ve uygun istisna atmak için iddiaları kullanabilirsiniz;)
Mr.Q

@ Mr.Q Ve bunun NullPointerExceptionatılması gerektiğini düşünüyorum: JDK'nın kullandığı ve arayüzler için gerektirdiği bir sözleşmedir, daha spesifiktir (tıpkı IndexOutOfBoundsExceptionvb. Gibi)
Solomon Ucko

kekekekkek ...: D
Yousha Aleayoub

17

Bu bir setteryöntem ve nullona geçiliyorsa, bence bir atmak daha mantıklı olacaktır IllegalArgumentException. A NullPointerException, gerçekten kullanmaya çalıştığınız durumda daha mantıklı görünüyor null.

Kullanmaya konum ve eğer Yani, bu kadar null, NullPointer. İçeri geçti ve gören varsa öyle null, IllegalArgument.


9

Apache Commons Lang bir NullArgumentException özelliğine sahip burada tartışılan bazı şeyleri yapan özelliğine özelliğini genişletir ve tek kurucusu, null olmayan argümanın adını alır.

NullArgumentException veya IllegalArgumentException gibi bir şey atmanın istisnai durumları daha doğru bir şekilde tanımladığını hissediyorum, ancak meslektaşlarım ve ben Bloch'un konu hakkındaki tavsiyelerini ertelemeyi seçtik.


7
Bunu commons-lang3'ten kaldırdıklarını unutmayın: apache-commons.680414.n4.nabble.com/…
artbristol

7

Söylenenlere daha fazla katılamadı. Erken başarısız, hızlı başarısız. Oldukça iyi İstisna mantra.

Hangi İstisnanın atılacağı sorusu çoğunlukla kişisel zevk meselesidir. Aklımda IllegalArgumentException bir NPE kullanmaktan daha spesifik gibi görünüyor çünkü bana problemin yöntemi gerçekleştirirken oluşturulmuş olabilecek bir değerle değil, yönteme aktardığım bir argümanla ilgili olduğunu söylüyor.

2 sentim


7

Aslında, IllegalArgumentException veya NullPointerException'ı atma sorunu, benim alçakgönüllü görüşüme göre, Java'da istisna işlemeyi bilmeyen bir azınlık için sadece "kutsal bir savaş". Genel olarak, kurallar basittir ve aşağıdaki gibidir:

  • hata ayıklaması çok daha zor olan yasadışı durumlardan kaçınmak için argüman kısıtlama ihlalleri mümkün olduğunca hızlı (-> hızlı başarısız) olarak gösterilmelidir
  • herhangi bir nedenden dolayı geçersiz bir boş gösterici olması durumunda, NullPointerException durumunu atın
  • geçersiz bir dizi / koleksiyon dizini durumunda, ArrayIndexOutOfBounds atın
  • negatif dizi / koleksiyon boyutu durumunda NegativeArraySizeException
  • yukarıdakilerin kapsamına girmeyen ve başka bir özel istisna türüne sahip olmadığınız yasadışı bir argüman olması durumunda, IllegalArgumentException öğesini çöp sepeti olarak atın
  • Öte yandan, bazı geçerli nedenlerle hızlı başarısızlıkla önlenemeyen bir ALAN İÇİNDE bir sınırlama ihlali durumunda, IllegalStateException veya daha spesifik bir kontrol edilen istisna olarak yakalayın ve yeniden gönderin. Bu durumda asla orijinal NullPointerException, ArrayIndexOutOfBounds, vb geçmesine izin vermeyin!

Her türlü argüman kısıtlaması ihlalini IllegalArgumentException ile eşleme durumunda en az üç çok iyi neden vardır, üçüncüsü muhtemelen uygulamayı kötü stili işaretleyecek kadar şiddetlidir:

(1) Bir programcı, tüm bağımsız değişken kısıtlama ihlallerinin IllegalArgumentException ile sonuçlandığını güvenli bir şekilde kabul edemez, çünkü standart sınıfların büyük çoğunluğu, daha fazla özel bir tür istisna yoksa çöp sepeti yerine bu istisnayı kullanır. Tüm argüman kısıtlama ihlalleri durumlarını API'nizdeki IllegalArgumentException ile eşlemeye çalışmak, standart kütüphaneler çoğunlukla sizinkileri ihlal eden farklı kuralları izlediğinden ve API kullanıcılarınızın çoğu da bunları kullanacağından, programcıların hayal kırıklığına yol açar!

(2) İstisnaların eşlenmesi aslında tek mirasın neden olduğu farklı türde bir anormallikle sonuçlanır: Tüm Java istisnaları sınıftır ve bu nedenle yalnızca tek miras alınmasını destekler. Bu nedenle, alt sınıflar yalnızca birinden veya diğerinden miras alabileceğinden, hem NullPointerException'ı hem de IllegalArgumentException'ı gerçekten söyleyen bir istisna oluşturmanın bir yolu yoktur. Bu nedenle, bir null argüman durumunda bir IllegalArgumentException özel durumunun atanması, bir programın sorunu programlı olarak düzeltmeye çalıştığında, örneğin bir çağrı yinelemesine girerek API kullanıcılarının sorunların birbirinden ayırt edilmesini zorlaştırır!

(3) Eşleme aslında hata maskeleme tehlikesi yaratır: Bağımsız değişken kısıtlama ihlallerini IllegalArgumentException ile eşlemek için, herhangi bir kısıtlanmış argümanı olan her yöntemde bir dış deneme yakalaması kodlamanız gerekir. Ancak, bu catch bloğunda RuntimeException özelliğinin yakalanması söz konusu değildir, çünkü bu, bağımsız değişken kısıtlaması ihlallerinden kaynaklanmasalar bile, sizinkiler içinde kullanılan libery yöntemleri tarafından atılan belgelenmiş RuntimeExceptions öğelerinin eşleştirilmesi riskidir. Bu nedenle, çok spesifik olmanız gerekir, ancak bu çaba bile sizi yanlışlıkla başka bir API'nın (yani bir hata) belgelenmemiş bir çalışma zamanı istisnasını API'nizin IllegalArgumentException istisnasıyla eşlediğinizden korumaz.

Diğer yandan standart uygulama ile kurallar basit kalır ve istisnalar maskesiz ve spesifik kalır. Yöntem arayan için kurallar da kolaydır: - geçersiz bir değer ilettiğiniz için herhangi bir tür belgelenmiş çalışma zamanı istisnasıyla karşılaşırsanız, çağrıyı varsayılan olarak tekrarlayın (bu özel istisnalar için gereklidir) veya kodunuzu düzeltin - Öte yandan, belirli bir argüman kümesi için belgelenmeyen bir çalışma zamanı istisnasıyla karşılaşırsanız, kodlarının veya belgelerinin düzeltildiğinden emin olmak için yöntemin üreticilerine bir hata raporu gönderin.


6

Bir parametrenin geçersiz olduğunu bildirmek ve olabildiğince fazla ayrıntı vermek için IllegalArgumentException (String iletisi) kullanılması kabul edilen uygulama ... Yani, bir parametrenin null olmayan özel durum varken boş olduğunu belirledik. bunun gibi:

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

"NullPointerException" örtülü olarak kullanmak için neredeyse hiçbir nedeniniz yok. NullPointerException, null başvuru (Like toString () ) üzerinde kod yürütmeye çalıştığınızda Java Virtual Machine tarafından atılan bir istisnadır .


6

Bağımsız nulldeğişkenlere (ister NullPointerExceptionözel bir tür olsun) özel bir istisna atmak otomatik nullsınamayı daha güvenilir hale getirir . Bu otomatik test olduğu gibi yansıma ve varsayılan değerler kümesi ile yapılabilir Guava 's NullPointerTester. Örneğin NullPointerTester, aşağıdaki yöntemi çağırmayı dener ...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

... iki argüman listesiyle: "", nullve null, ImmutableList.of(). Bu çağrıların her birinin beklenenleri atar NullPointerException. Bu uygulama için, yoldan geçen bir nullliste yok değil üretmek NullPointerException. Bununla beraber, bir üretme oluyor IllegalArgumentExceptionçünkü NullPointerTestervarsayılan dizesi kullanmak olur "". Eğer NullPointerTestersadece beklentiden NullPointerExceptioniçin nulldeğerler, bu hata yakalar. O bekliyorsa IllegalArgumentException, onu özlüyor.


5

Bazı koleksiyonlar bunun yerine nullkullanılarak reddedildiğini varsayar . Örneğin, içeren bir kümeyi reddeden bir kümeyle karşılaştırırsanız , ilk küme diğerini çağırır ve kümesini yakalar, ancak yakalamaz . (Uygulamasına bakıyorumNullPointerExceptionIllegalArgumentExceptionnullnullcontainsAllNullPointerExceptionIllegalArgumentExceptionAbstractSet.equals .)

Sen makul ihtiva karşılaştıran koleksiyonları olduğunu, bu şekilde kontrolsüz istisnaları kullanan bir antipattern olduğunu iddia olabilir nulliçeremez koleksiyonlarına nullgerçekten bir olasılıkla hata olduğunu gerekir bir istisna üretmek veya koyarak o nullhiç bir koleksiyon kötü bir fikirdir . Bununla birlikte, equalsböyle bir durumda bir istisna atması gerektiğini söylemeye istekli değilseniz NullPointerException, bazı durumlarda gerekli olduğunu , ancak başkalarında gerekli olmadığını hatırlamakta zorlanıyorsunuz. ("NPE öncesi IAE, 'c' hariç ...")


Koleksiyonun içindeki bir öğeye bağlı olarak içeriğin nasıl bir NPE attığını görmüyorum. Bir NPE'nin (afaict) atılmasının tek nedeni, koleksiyonun kendisinin null olmasıdır (bu durumda NPE, yineleyiciye erişmeye çalıştığı için atılır). Ancak bu, boş girişin kontrol edilmesi gerekip gerekmediği veya erişilmeye çalışılana kadar yayılması gerekip gerekmediği sorusunu gündeme getirir.
Alowaniak

2
new TreeSet<>().containsAll(Arrays.asList((Object) null));atar NPEçünkü Listiçeriyor null.
Chris Povirk

1
Gerçekten de, TreeSet # "belirtilen öğe null ise ve bu küme doğal sıralama kullanıyorsa veya karşılaştırıcısı null öğelere izin vermiyorsa" NPE atar. Sadece null'a izin veren AbstractSet'e baktım, kötülerim. Şahsen ben sadece yanlış döndürmek değil garip buluyorum, çünkü bu durumda bir null eklenen olamaz.
Alowaniak

5

Sübjektif bir soru olarak bu kapatılmalıdır, ancak hala açık olduğu için:

Bu benim önceki istihdam yerimde kullanılan iç politikanın bir parçası ve gerçekten iyi çalıştı. Bu tamamen hafızadan, bu yüzden tam ifadeyi hatırlayamıyorum. İşaretli istisnaları kullanmadıklarını belirtmek gerekir, ancak bu sorunun kapsamı dışındadır. Kullandıkları kontrolsüz istisnalar 3 ana kategoriye ayrıldı.

NullPointerException: Kasten atmayın. NPE'ler, boş bir başvurunun kaydı kaldırılırken yalnızca VM tarafından atılır. Bunların asla atılmamasını sağlamak için mümkün olan tüm çaba gösterilmelidir. Bu hataları bulmak için @Nullable ve @NotNull kod analiz araçlarıyla birlikte kullanılmalıdır.

IllegalArgumentException: Bir işleve yönelik bir argüman, genel belgelere uymadığında, hatanın iletilen argümanlar açısından tanımlanıp tanımlanabileceği şekilde atılır. OP'nin durumu bu kategoriye girer.

IllegalStateException: Bir işlev çağrıldığında ve bağımsız değişkenleri iletildikleri sırada beklenmedik olduğunda veya yöntemin üyesi olduğu nesnenin durumuyla uyumsuz olduğunda atılır.

Örneğin, IndexOutOfBoundsException öğesinin uzunluğu olan şeylerde kullanılan iki dahili sürümü vardı. Bir tanesi, dizin uzunluktan büyükse, IllegalStateException alt sınıfını kullanır. Diğeri, dizin negatifse kullanılan IllegalArgumentException alt sınıfı. Bunun nedeni, nesneye daha fazla öğe ekleyebilmeniz ve bağımsız değişken geçerli olurken negatif bir sayı hiçbir zaman geçerli olmamasıdır.

Dediğim gibi, bu sistem gerçekten iyi çalışıyor ve ayrımın neden orada olduğunu açıklamak birisini aldı: "Hata türüne bağlı olarak, ne yapacağınızı anlamanız oldukça basittir. neyin yanlış gittiğini bu hatayı nerede yakalayacağınızı anlayabilir ve ek hata ayıklama bilgileri oluşturabilirsiniz. "

NullPointerException: Null durumunu işleyin veya NPE'nin atılmaması için bir iddiada bulunun. Bir iddiada bulunursanız, diğer iki türden sadece bir tanesidir. Mümkünse, ilk başta iddianın olduğu gibi hata ayıklamaya devam edin.

IllegalArgumentException: çağrı sitenizde bir sorun var. Aktarılan değerler başka bir işlevdeyse, neden yanlış bir değer aldığınızı öğrenin. Argümanlarınızdan birini geçiriyorsanız, beklediğiniz şeyi döndürmeyen işlevi bulana kadar hata çağrı yığınını kontrol eder.

IllegalStateException: İşlevlerinizi doğru sırada çağırmadınız. Bağımsız değişkenlerinizden birini kullanıyorsanız, bunları kontrol edin ve sorunu açıklayan bir IllegalArgumentException durumu oluşturun. Daha sonra sorunu bulana kadar yanakları yığına doğru ilerletebilirsiniz.

Her neyse, onun amacı, sadece IllegalArgumentAssertions'ı yığına kopyalayabilmenizdi. IllegalStateExceptions veya NullPointerExceptions'ı yığına yaymanın bir yolu yoktur, çünkü işlevinizle ilgili bir şeyleri vardı.


4

Genel olarak, bir geliştirici asla bir NullPointerException oluşturmamalıdır. Kodun değeri null olan bir değişkeni elden çıkarmaya çalıştığında bu istisna çalışma zamanı tarafından atılır. Bu nedenle, yönteminiz bir nullPointerException özel değeri yükseltmek yerine, null değerini açıkça reddetmek istiyorsa, bir IllegalArgumentException özel durumu atamalısınız.


9
NPE üzerinde JavaDoc başka bir görüşe sahiptir: "Uygulamalar null nesnesinin diğer yasadışı kullanımlarını belirtmek için bu sınıfın örneklerini atmalıdır.". Çok kategorik olmayın
Donz

4

Null argümanlarını diğer yasadışı argümanlardan ayırmak istedim, bu yüzden IAE'den NullArgumentException adlı bir istisna türettim. İstisna mesajını okumaya bile gerek kalmadan, bir yönteme null argüman aktarıldığını biliyorum ve mesajı okuyarak hangi argümanın null olduğunu buldum. Hala bir IAE işleyicisi ile NullArgumentException yakalamak, ama günlükleri fark hızlı bir şekilde görebiliyor.


"Yeni IllegalArgumentException atmak (" foo == null ")" yaklaşımını benimsedim. Değişken adını yine de kaydetmelisiniz (doğru sttata vb. Baktığınızdan emin olmak için)
Thorbjørn Ravn Andersen

4

ikilik ... Üst üste binmiyor mu? Bir bütünün yalnızca örtüşmeyen kısımları bir ikilem yapabilir. Gördüğüm kadarıyla:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

1
Bu, istisna oluşturmak için ek yükü iki katına çıkarır ve yakalamanın NullPointerExceptionhiçbir şey yapmaması nedeniyle gerçekten yardımcı olmaz. Yardımcı olabilecek tek şey IllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerException, ama birden fazla mirasımız yok.
maaartinus

Daha spesifik istisnaların, daha genel istisnalarla sarılması gerektiğine inanıyorum. NPE bir ifade, IAE ise bir yöntem içindir. Yöntemler ifadeleri içeren ifadeler içerdiğinden, IAE daha geneldir.
Sgene9

Genel gider konusunda hiçbir fikrim yok. Ancak yığın izleri, istisna adının ortada değişmesi dışında temel olarak aynı olacağından, çift istisnalar için çok fazla ek yük olmaması gerektiğini düşünüyorum. Birisi yükten endişe duyuyorsa, istisna atmak yerine null veya -1 döndürmek için "if" ifadelerini kullanabilir.
Sgene9

4

NullPointerExceptionGeçerli değeri olan bir referans değişkeni olan bir nesneye erişmeye çalışıldığında atılır null.

IllegalArgumentException bir yöntem, yöntemin beklediğinden farklı biçimlendirilmiş bir bağımsız değişken aldığında atılır.


3

Senaryonuza göre IllegalArgumentException, en iyi seçimdir, çünkü nullmülkünüz için geçerli bir değer değildir.


0

İdeal olarak çalışma zamanı istisnaları atılmamalıdır. Senaryonuz için kontrol edilmiş bir istisna (iş istisnası) oluşturulmalıdır. Çünkü bu istisnalardan herhangi biri atılır ve günlüğe kaydedilirse, günlükleri incelerken geliştiriciyi yanlış yönlendirir. Bunun yerine, iş istisnaları bu paniği oluşturmaz ve günlük sorunlarını giderirken genellikle yok sayılır.


-1

Yukarıdaki iki istisna için yapılan bağlantıların tanımları IllegalArgumentException'dır: Bir yöntemin geçersiz veya uygunsuz bir argümandan geçirildiğini belirtmek için atılır. NullPointerException: Bir nesnenin gerekli olduğu bir durumda uygulama null kullanmaya çalıştığında atılır.

Buradaki en büyük fark, bir yönteme yönelik bir argümanın geçerli olup olmadığını kontrol ederken IllegalArgumentException özelliğinin kullanılması gerektiğidir. NullPointerException bir nesne null olduğunda "kullanıldığında" kullanılmalıdır.

Umarım bu ikisini perspektife sokar.


1
Belirgin bit, çalışma zamanı değil null kullanan uygulama olmasıdır. Dolayısıyla, "bir yöntem yasadışı veya uygunsuz bir argümandan geçildiğinde" ile "bir uygulama null kullanıyorsa" arasında oldukça büyük bir çakışma vardır. Teorik olarak, bir uygulama null olmayan bir alan için null değerini geçerse, her iki kriter de karşılanmaktadır.
Christopher Smith

-1

Bir "ayarlayıcı" veya daha sonra kullanmak için bir üye alıyorum bir yerde, IllegalArgumentException kullanmak eğilimindedir.

Şu anda yöntemde (dereference) kullanacağım bir şey varsa, proaktif olarak bir NullPointerException oluştururum. Ben yararlı bir mesaj sağlayabilir çünkü çalışma zamanı izin izin daha iyi gibi (çalışma zamanı da bunu yapabilir gibi görünüyor, ama bu başka bir gün için bir rant).

Bir yöntemi geçersiz kılarsam, geçersiz kılınan yöntem ne kullanırsa onu kullanırım.


-1

Programcıya geçersiz bir şey yaptığını açıkça göstereceği için bir IllegalArgumentException istisnası atmalısınız. Geliştiriciler, VM tarafından atılan NPE'yi görmeye o kadar alışkın ki, herhangi bir programcı hatasını hemen fark etmeyecek ve rastgele veya daha kötüsü, 'buggy' olduğu için kodunuzu suçlamaya başlayacaktı.


4
Maalesef, bir programcı herhangi bir istisna olduğunda "rastgele" etrafına bakarsa ... bir istisnanın adını değiştirmek pek yardımcı olmaz.
Christopher Smith

-1

Bu durumda, IllegalArgumentException, API'nızı kullanarak kullanıcıya "boş olmamalı" konusunda net bilgiler iletir. Diğer forum kullanıcılarının işaret ettiği gibi, API'nızı kullanarak doğru bilgileri kullanıcıya iletmek istediğiniz sürece NPE'yi kullanabilirsiniz.

GaryF ve tweakt "Etkili Java" (yemin ederim) NPE kullanmanızı tavsiye referanslar düştü. Diğer iyi API'lerin nasıl oluşturulduğuna bakmak, API'nizi nasıl oluşturacağınızı görmenin en iyi yoludur.

Diğer iyi bir örnek de Bahar API'larına bakmaktır. Örneğin, org.springframework.beans.BeanUtils.instantiateClass (Yapıcı ctor, Object [] args) bir Assert.notNull (ctor, "Constructor null olmamalıdır") satırına sahiptir. org.springframework.util.Assert.notNull (Object object, String message) yöntemi, iletilen bağımsız değişkenin (object) null olup olmadığını kontrol eder ve eğer yeni bir IllegalArgumentException (message) atar ve bu da org'a yakalanır. springframework.beans.BeanUtils.instantiateClass (...) yöntemi.


-5

Bir NPE atmayı seçerseniz ve yönteminizde bağımsız değişkeni kullanıyorsanız, bir null olup olmadığını açıkça denetlemek gereksiz ve pahalı olabilir. Bence VM bunu sizin için zaten yapıyor.


Çalışma süresi anlamlı bir msj içermez.
mP.

Aslında bu yorum başka bir fikir doğurabilir. VM'nin konuşmasına izin verin, NPEancak programcılar IAEisterse VM'den önce konuşurlar .
Jin Kwon

1
Pahalı? Ben == null bu kadar pahalı olduğunu sanmıyorum ... Ayrıca, null argüman sadece ikinci kullanım için saklanabilir ve yöntem çağrısından sonra uzun bir istisna atacak, hatayı izlemek daha zor hale getirir. Veya null bağımsız değişkenini kullanmadan önce pahalı bir nesne oluşturabilirsiniz. Erken teşhis iyi bir seçenek gibi görünmektedir.
PhiLho

bu cevabın aşağı oylanması, arkadaki donanımın yanlış anlaşılmasıdır. Kesinlikle donanım kontrolleri (CPU'nun yaptığı) açık kontrolden daha ucuzdur. Null'un kaydının kaldırılması, CPU / OS'nin kontrol ettiği ve JRE'nin NullPointerException özel durumlarını işleyen özel bir durum olarak işlediği SegmentationFault (SegV) özel durumudur (işlemin sahip olmadığı bir sayfaya erişim).
digital_infinity
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.