NullPointerException nedir ve nasıl düzeltebilirim?


210

Boş İşaretçi İstisnaları ( java.lang.NullPointerException) nedir ve bunlara neden olan nedir?

İstisnanın programın erken sonlandırılmasına neden olmasını önlemek için nedeni belirlemek için hangi yöntemler / araçlar kullanılabilir?

Yanıtlar:


3764

Bir referans değişkeni (yani bir nesne) bildirdiğinizde, gerçekten bir nesneye işaretçi oluşturursunuz. İlkel tipte bir değişken bildirdiğinizde aşağıdaki kodu göz önünde bulundurun int:

int x;
x = 10;

Bu örnekte, değişken xbir intve Java bunu 0sizin için başlatacaktır . 10İkinci satıra değerini atadığınızda, değeriniz 10atıfta bulunulan bellek konumuna yazılır x.

Ancak, bir başvuru türü bildirmeye çalıştığınızda , farklı bir şey olur. Aşağıdaki kodu alın:

Integer num;
num = new Integer(10);

İlk satır adlı bir değişken bildirir num, ancak aslında henüz ilkel bir değer içermez. Bunun yerine, bir işaretçi içerir (çünkü tür Integerbir referans türüdür). Neye işaret edeceğinizi henüz söylemediğiniz için Java bunu null" hiçbir şeye işaret etmiyorum " anlamına gelir .

İkinci satırda, newanahtar kelime türünde bir nesneyi başlatmak (veya oluşturmak) için kullanılır Integerve işaretçi değişkeni numo Integernesneye atanır .

NullPointerExceptionBir değişkeni bildirir ancak değişkenin (denilen içeriğini kullanmayı denemeden önce değişkene bir nesne ve ata yaratmadı oluşur başvurusu kaldırma ). Yani aslında var olmayan bir şeye işaret ediyorsunuz.

Dereferencing genellikle .bir yönteme veya alana erişmek için kullanılırken veya [bir dizini dizine eklemek için kullanılır .

numNesneyi oluşturmadan ÖNCE kayıttan ayrılmaya çalışırsanız, bir NullPointerException. En önemsiz durumlarda, derleyici sorunu yakalar ve bunu " num may not have been initialized," size bildirir , ancak bazen doğrudan nesneyi oluşturmayan bir kod yazabilirsiniz.

Örneğin, aşağıdaki gibi bir yönteminiz olabilir:

public void doSomething(SomeObject obj) {
   //do something to obj
}

Bu durumda, nesneyi oluşturmazsınız obj, bunun yerine doSomething()yöntem çağrılmadan önce oluşturulduğunu varsayarsınız . Not, yöntemi şöyle çağırmak mümkündür:

doSomething(null);

Bu durumda, objbir null. Yöntemin, iletilen nesneye bir şey yapması amaçlanıyorsa, NullPointerExceptionbir programcı hatası olduğu ve programcının hata ayıklama amacıyla bu bilgilere ihtiyacı olacağı için atmak uygundur . Lütfen istisna iletisine nesne değişkeninin adını ekleyin.

Objects.requireNonNull(a, "a");

Alternatif olarak, yöntemin amacının yalnızca iletilen nesnede çalışması olmadığı ve bu nedenle bir boş parametrenin kabul edilebilir olduğu durumlar olabilir. Bu durumda, null parametresini kontrol etmeniz ve farklı davranmanız gerekir. Bunu belgelerde de açıklamalısınız. Örneğin, doSomething()şu şekilde yazılabilir:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj == null) {
       //do something
    } else {
       //do something else
    }
}

Son olarak, Yığın İzi'ni kullanarak kural dışı durumu ve nedeni belirleme

İstisnanın programın erken sonlandırılmasına neden olmasını önlemek için nedeni belirlemek için hangi yöntemler / araçlar kullanılabilir?

Findbugs ile Sonar NPE tespit edebilir. Sonar, dinamik olarak JVM'nin neden olduğu boş gösterici istisnalarını yakalayabilir mi


558
"Bu tür bir istisnayı önlemenin en iyi yolu, nesneyi kendiniz oluşturmadığınızda her zaman null olup olmadığını kontrol etmektir." Arayan kişi null değerini iletir, ancak null yöntem için geçerli bir bağımsız değişken değilse, arayanın hatası olduğu için istisnayı arayana atmak doğrudur. Geçersiz girişi sessizce göz ardı etmek ve yöntemde hiçbir şey yapmamak , sorunu gizlediği için son derece zayıf bir tavsiye.
Boann

104
Bu yazı hakkında, ilkellere yapılan atamaların bile otomatik boks kullanırken NPE'lere neden olabileceğini açıklayan bir açıklama ekleyeceğim: int a=bb ise bir NPE atabilir Integer. Bunun hata ayıklamak için kafa karıştırıcı olduğu durumlar vardır.
Simon Fischer

58
Web tarayıcısından bir web uygulaması tarafından atılan NPE'yi yakalamak mümkün mü? Web tarayıcısından görünüm sayfası kaynağında gösterileceği gibi ..
Sid

76
Evet, bir yöntemi çağırmadan önce nesnenin null değerine eşit olup olmadığını kontrol edin veya sahip olabileceği bir değişkene erişmeye çalışın. Kodunuzu yapılandırmak bazen boş işaretçi istisnasını önlemeye yardımcı olabilir. Örneğin, bir giriş dizesini sabit bir dizeyle kontrol ederken, aşağıdaki gibi sabit dizeyle başlamalısınız: if ("SomeString" .equals (inputString)) {} // inputString boş olsa bile istisna atılmaz. Bu yüzden güvende olmak için yapabileceğiniz bir sürü şey var.
Gül

78
NullPointerExceptionKodunuzdaki sorunlardan kaçınmanın ek bir yolu kullanmak @Nullableve @NotNullek açıklamaları kullanmaktır . Aşağıdaki cevap bu konuda daha fazla bilgi içerir. Bu yanıt özellikle IntelliJ IDE ile ilgili olsa da, yorumlardan da anlaşılacağı gibi diğer araçlar için de geçerlidir. (BTW Bu yanıtı doğrudan düzenlememe izin verilmiyor, belki yazar ekleyebilir mi?)
Arjan Mels

879

NullPointerExceptions, bir nesneye başvuruyormuş gibi bellekte (null) hiçbir yere işaret etmeyen bir başvuru kullanmaya çalıştığınızda oluşan özel durumlardır. Bir null referanstaki bir yöntemi çağırmak veya null referansın bir alanına erişmeye çalışmak a NullPointerException. Bunlar en yaygın olanlarıdır, ancak diğer yollar NullPointerExceptionjavadoc sayfasında listelenmiştir .

Muhtemelen en hızlı örnek kodu ben bir göstermek için gelip NullPointerExceptionolabilir:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

İçerideki ilk satırda main, Objectreferansı açıkça objeşit olarak ayarlıyorum null. Bu bir referansım olduğu anlamına geliyor, ancak herhangi bir nesneye işaret etmiyor. Bundan sonra, başvuruyu, bir yöntemi çağırarak bir nesneye işaret ediyormuş gibi ele almaya çalışıyorum. Bunun NullPointerExceptionnedeni, başvurunun işaret ettiği konumda yürütülecek kod olmamasıdır.

(Bu bir tekniktir, ancak bahsettiğini düşünüyorum: null değerine işaret eden bir başvuru, geçersiz bir bellek konumuna işaret eden bir C işaretçisiyle aynı değildir. Null işaretçisi tam anlamıyla hiçbir yere işaret etmiyor , geçersiz olan bir yere işaret ediyor.)


49
Orada yazdığınız her şeyi anladım, ama sadece bir süredir kodladığım ve bir 'işaretçi' ve bir 'referansın' ne olduğunu (ve bu konuda null olduğunu) bildiğim için. Bunun gibi açıklamalara dalmaya çalıştığımda, öğrencilerim bana çapraz olarak baktı, çünkü yeterli arka plan yok.
mmr

33
@ mmr: Geri bildiriminiz için teşekkürler, geçerli bir noktaya değindiniz. İnternette birisinin nerede olduğunu ve hangi seviyede bir açıklama başlatmanın güvenli olduğunu gerçekten belirlemek zor. Bunu tekrar gözden geçirmeyi deneyeceğim.
Kertenkele Bill

22
Uygulamada bir NullPointerException almak için daha yaygın yolu açıkça dışında bir üye değişkeni başlatmak unutmak olacağını null, kullanmadan önce böyle . Yerel değişkenlerde, derleyici bu hatayı yakalar, ancak bu durumda yakalamaz. Belki bu cevabınıza faydalı bir katkı yapar mı?
Ilmari Karonen

6
@EJP Puanlarınızın geçerli olduğunu düşünüyorum, bu yüzden cevabı daha net olacak ve nerede 'null'a puan' demekten kaçınacak şekilde güncelledim.
Steve Powell

5
@StevePowell Uzun zaman önce cevabımın değişmesini istemediğimi söyledim. Lütfen asıl yazarın amacına saygı gösterin.
Kertenkele Bill

696

NullPointerException nedir?

Başlamak için iyi bir yer JavaDocs . Bunları kapsamaktadır:

Bir uygulama, bir nesnenin gerekli olduğu bir durumda null kullanmaya çalıştığında atılır. Bunlar:

  • Boş bir nesnenin örnek yöntemini çağırma.
  • Boş bir nesnenin alanına erişme veya bu nesneyi değiştirme.
  • Null uzunluğunu bir diziymiş gibi almak.
  • Null yuvalarına bir diziymiş gibi erişme veya bunları değiştirme.
  • Atılabilir bir değermiş gibi boş atıyor.

Uygulamalar null nesnesinin diğer yasadışı kullanımlarını belirtmek için bu sınıfın örneklerini atmalıdır.

Ayrıca bir null başvuru kullanmaya kalkarsanız Eğer durum synchronizedda, bu istisna durumu, JLS başına :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • Aksi takdirde, İfadenin değeri null olursa a NullPointerExceptionatılır.

Nasıl düzeltebilirim?

Yani bir tane var NullPointerException. Nasıl tamir edersin? A atarak basit bir örnek verelim NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Boş değerleri belirleme

İlk adım, istisnaya hangi değerlerin tam olarak neden olduğunu tanımlamaktır . Bunun için hata ayıklama yapmamız gerekiyor. Bir yığın izini okumayı öğrenmek önemlidir . Bu size istisnanın nereye atıldığını gösterecektir:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Burada, istisnanın 13. hatta ( printStringyöntemde) atıldığını görüyoruz . Satıra bakın ve günlük kaydı ifadeleri ekleyerek veya bir hata ayıklayıcı kullanarak hangi değerlerin boş olduğunu kontrol edin . Bunun snull lengtholduğunu öğrendik ve üzerine yöntemin çağrılması istisnayı atar. s.length()Yöntemden kaldırıldığında programın istisnayı atmayı bıraktığını görebiliriz.

Bu değerlerin nereden geldiğini izleyin

Sonra bu değerin nereden geldiğini kontrol edin. Yöntemin arayanları takip ederek, biz görüyoruz sİle geçirilir printString(name)içinde print()yöntemle ve this.nameboş.

Bu değerlerin nerede ayarlanacağını izleyin

Nerede this.nameayarlanır? İn setName(String)yöntemi. Daha fazla hata ayıklama ile, bu yöntemin hiç çağrılmadığını görebiliriz. Yöntem denilen ise, mutlaka kontrol edin emri bu yöntemler dendiğini ve set yöntemi çağrılmaz sonra baskı yöntemiyle.

Bu bize bir çözüm sunmak için yeterlidir: printer.setName()aramadan önce bir çağrı ekleyin printer.print().

Diğer düzeltmeler

Değişkenin varsayılan bir değerisetName olabilir (ve null değerine ayarlanmasını engelleyebilirsiniz):

private String name = "";

Her iki printya da printStringyöntem olabilir boş kontrol , örneğin:

printString((name == null) ? "" : name);

Veya sınıfı name her zaman boş olmayan bir değere sahip olacak şekilde tasarlayabilirsiniz :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

Ayrıca bakınız:

Sorunu hala bulamıyorum

Sorunu ayıklamaya çalıştıysanız ve hala bir çözümünüz yoksa, daha fazla yardım için bir soru gönderebilirsiniz, ancak şimdiye kadar denediklerinizi eklediğinizden emin olun. En azından, soruya yığın izini ekleyin ve koddaki önemli satır numaralarını işaretleyin . Ayrıca, önce kodu basitleştirmeyi deneyin (bkz. SSCCE ).


44
+1 Yığın izinden geçmeyi içeren bir örnek olması iyi; NPE hata ayıklaması için okumanın neden önemli olduğunu göstermek önemlidir. (ve neden hemen hemen her zaman bir stacktrace aramaya kişi yayın bir hata hakkında bir soru)
Dennis Meng

16
Hata ayıklamadan bahsettiniz ... Bu nasıl çalışır? Bir süredir konuyu araştırıyorum, ancak hiçbir şey bulamıyorum. Eminim senin gibi inanılmaz bir öğretmen bir saniye içinde bana öğretebilir! Çok teşekkürler! :-)
Ruchir Baronia

15
@RuchirBaronia Hata ayıklayıcı, hangi yöntemlerin çağrıldığını ve değişkenlerin nasıl değiştirildiğini görmek için bir program satır satır ilerlemenizi sağlar. IDE'lerin bunu yapmak için bazı araçları olmalıdır. Örneğin vogella.com/tutorials/EclipseDebugging/article.html adresine bakın .
fgb

15
@RuchirBaronia Yığın izinde görüldüğü gibi, herhangi bir NullPointerExceptions çevresindeki yöntemlerde kesme noktaları ayarlarsınız ve değişkenlerin değerlerini olmasını beklediğiniz değerlere göre denetlersiniz. Değişkenin olmaması gerektiğinde null olduğunu biliyorsanız, değeri değiştiren herhangi bir kodun çevresinde kesme noktaları ayarlayabilirsiniz. Ayrıca, bir değer değiştiğinde size söyleyecek koşullu kesme noktaları da vardır.
fgb

6
Dize nesnelerini varsayılan değer olarak boş bir dizeye ayarlamak zayıf bir uygulama olarak kabul edilir.
Küçük

501

Soru: NullPointerException(NPE) nin nedeni nedir ?

Bildiğiniz gerektiği gibi, Java tipleri ayrılır ilkel türleri ( boolean, intvs.) ve referans türleri . Java'daki başvuru türleri, null"nesne yok" demenin Java yöntemi olan özel değeri kullanmanızı sağlar .

NullPointerExceptionProgramınız nullgerçek bir referansmış gibi a kullanmaya çalıştığında çalışma zamanında A atılır . Örneğin, bunu yazarsanız:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

"HERE" etiketli ifade length()yöntemi bir nullbaşvuru üzerinde çalıştırmayı dener ve bu a'yı atar NullPointerException.

A ile nullsonuçlanacak bir değeri kullanmanın birçok yolu vardır NullPointerException. Aslında, o tek şey olabilir bir ilgisi nullbir NPE neden olmadan şunlardır:

  • bir referans değişkenine atayabilir veya bir referans değişkeninden okuyabilir,
  • bir dizi öğesine atayabilir veya bir dizi öğesinden okuyabilir (dizi referansının kendisinin boş olmaması şartıyla!),
  • parametre olarak iletin veya sonuç olarak geri gönderin veya
  • ==veya !=işleçlerini kullanarak sınayın veya instanceof.

Soru: NPE yığın izini nasıl okurum?

Yukarıdaki programı derlediğimi ve çalıştırdığımı varsayalım:

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

İlk gözlem: derleme başarılı! Programdaki sorun bir derleme hatası DEĞİLDİR. Bir çalışma zamanı hatasıdır. (Bazı IDE'ler programınızın her zaman bir istisna atacağı konusunda uyarabilir ... ancak standart javacderleyici bunu yapmaz.)

İkinci gözlem: programı çalıştırdığımda, iki satır "gobbledy-gook" çıktısı verir. YANLIŞ!! Bu gobbledy-gook değil. Bu bir yığın izidir ... ve dikkatlice okumak için zaman ayırırsanız kodunuzdaki hatayı izlemenize yardımcı olacak hayati bilgiler sağlar .

Öyleyse ne dediğine bakalım:

Exception in thread "main" java.lang.NullPointerException

Yığın izinin ilk satırı size birkaç şey anlatır:

  • Size istisnanın atıldığı Java iş parçacığının adını söyler. Bir iş parçacığı (bu gibi) ile basit bir program için, "ana" olacaktır. Hadi devam edelim ...
  • Size atılan istisnanın tam adını söyler; yani java.lang.NullPointerException.
  • Kural dışı durumun ilişkili bir hata mesajı varsa, kural dışı durum adından sonra verilir. NullPointerExceptionbu konuda alışılmadık bir durumdur, çünkü nadiren bir hata mesajı vardır.

İkinci çizgi, NPE tanısında en önemli olanıdır.

at Test.main(Test.java:4)

Bu bize birkaç şey söyler:

  • "at Test.main" sınıf mainyönteminde olduğumuzu söylüyor Test.
  • "Test.java:4" sınıfın kaynak dosya adını verir ve bize bunun gerçekleştiği ifadenin dosyanın 4. satırında olduğunu söyler.

Yukarıdaki dosyadaki satırları sayarsanız, 4. satır "BURAYA" yorumuyla etiketlediğim satırdır.

Daha karmaşık bir örnekte, NPE yığın izlemesinde çok sayıda satır olacağını unutmayın. Ancak ikinci satırın (ilk "at" satırının) size NPE'nin nereye atıldığını söyleyeceğinden emin olabilirsiniz 1 .

Kısacası, yığın izleme bize programın hangi ifadesinin NPE'yi attığını açık bir şekilde söyleyecektir.

1 - Pek doğru değil. İç içe istisnalar denen şeyler var ...

Soru: Kodumdaki NPE özel durumunun nedenini nasıl izlerim?

Zor kısmı bu. Kısa cevap, yığın izlemesi, kaynak kodu ve ilgili API dokümantasyonu tarafından sağlanan kanıtlara mantıksal çıkarım uygulamaktır.

Önce basit örnekle (yukarıda) açıklayalım. Yığın izinin bize NPE'nin nerede olduğunu söylediği çizgiye bakarak başlarız:

int length = foo.length(); // HERE

Bu nasıl bir NPE fırlatabilir?

Aslında, tek bir yol vardır: bu sadece foodeğere sahipse olabilir null. Daha sonra length()yöntemi çalıştırmaya çalışıyoruz nullve ... BANG!

Ama (dediğini duyuyorum) ya NPE length()yöntem çağrısının içine atılırsa ?

Eğer bu olsaydı, yığın izi farklı görünürdü. İlk "at" satırı, istisnanın java.lang.Stringsınıftaki bir satıra atıldığını ve 4. satırının Test.javaikinci "at" satırı olacağını söyler .

Peki bu nullnereden geldi? Bu durumda, açıktır ve düzeltmek için ne yapmamız gerektiği açıktır. (Konumuna boş olmayan bir değer atayın foo.)

Tamam, biraz daha zor bir örnek deneyelim. Bu biraz mantıksal kesinti gerektirecektir .

public class Test {

    private static String[] foo = new String[2];

    private static int test(String[] bar, int pos) {
        return bar[pos].length();
    }

    public static void main(String[] args) {
        int length = test(foo, 1);
    }
}

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.test(Test.java:6)
    at Test.main(Test.java:10)
$ 

Şimdi iki tane "satır" çizgimiz var. İlki bu çizgi için:

return args[pos].length();

ve ikincisi bu çizgi içindir:

int length = test(foo, 1);

İlk satıra bakıldığında, bu nasıl bir NPE fırlatabilir? İki yol vardır:

  • Değeri bar, nullo bar[pos]zaman bir NPE atar.
  • Değeri ise bar[pos]edilir nulldaha sonra arayarak length()üzerine bir NPE atar.

Sonra, bu senaryolardan hangisinin gerçekte neler olduğunu açıkladığını bulmamız gerekiyor. İlkini keşfederek başlayacağız:

Nereden bargeliyor? Bu, testyöntem çağrısının bir parametresidir ve nasıl testçağrıldığına bakarsak, foostatik değişkenden geldiğini görebiliriz . Ayrıca, foonull olmayan bir değere başlattığımızı açıkça görebiliriz . Bu açıklamayı geçici olarak reddetmek yeterlidir. (Teorik olarak, başka bir şey olabilir değiştirmek foo için null... ama bu burada olmuyor.)

İkinci senaryomuz ne olacak? Eh, biz görebilirsiniz posolduğunu 1, bu yollarla böylece foo[1]olmalıdır null. Mümkün mü?

Gerçekten öyle! ve problem bu. Bu şekilde başlattığımızda:

private static String[] foo = new String[2];

Biz tahsis String[]iki unsurları ile başlatılırnull . Bundan sonra, içeriğini değiştirmedik foo... öyle foo[1]olmayacak null.


425

Sanki bir nesneye erişmeye çalışıyorsun null. Aşağıdaki örneği düşünün:

TypeA objA;

Şu anda bu nesneyi yeni beyan ettiniz, ancak başlatılmadınız veya somutlaştırılmadınız . Ve içindeki herhangi bir mülke veya yönteme erişmeye çalıştığınızda NullPointerException, mantıklı olacaktır.

Aşağıdaki örneğe de bakın:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown

1
System.out.println (a.length ()) verirsek; // NullPointerException atılacak, bunu atlamak için try catch bloğu ile başa çıkabiliriz. teşekkür ederim
Vijaya Varma Lanke

359

Bir uygulama bir nesnenin gerekli olduğu bir durumda null kullanmaya çalıştığında bir boş işaretçi istisnası atılır. Bunlar:

  1. Bir nullnesnenin örnek yöntemini çağırma .
  2. Bir nullnesnenin alanına erişme veya alanın üzerinde değişiklik yapma .
  3. nullBir dizi gibi uzunluğunu almak .
  4. nullSanki bir diziymiş gibi yuvalarına erişme veya bunları değiştirme .
  5. Fırlatma nullbir Atılabil değer sanki.

Uygulamalar, nullnesnenin diğer yasadışı kullanımlarını belirtmek için bu sınıfın örneklerini atmalıdır.

Referans: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html


12
Basit tutun, bu yanıtı beğendim, doğru olduğunu düşünüyorsanız bunu ekleyin - Bir nesnenin başlatılmamış özniteliğine erişim
Emiliano

5
@Emiliano - başlatılmış bir özniteliğe erişmek NPE'ye neden olmaz. NPE'ye neden olan başlatılmamış öznitelik değeriyle << yaparsınız.
Stephen C

1
1) Bir kullanarak: Daha fazla vaka istiyorsanız nullbir hedefi olarak synchronizedbloğunun, 2) kullanılarak nullbir hedefi olarak switchve unboxing null.
Stephen C

333

Bir nullişaretçi hiçbir için bir o puandır. Bir işaretçi çözümlemesi yaparken p, sen p "saklanan yerde bana veri sağlamak 'demek'. Ne zaman pbir olan nullişaretçi, depolanan yer palmaktadır nowherediyorsunuz '' 'hiçbir' yerde bana veriler gösterir. Açıkçası, bunu yapamaz, bu yüzden a atar null pointer exception.

Genel olarak, bunun nedeni bir şeyin doğru şekilde başlatılmamış olmasıdır.


2
Bir veritabanı mı oluşturuyoruz? -> java NULLdilinde yazılmıştır null. Ve bu büyük / küçük harfe duyarlı bir şey.
bvdb

3
"NULL işaretçisi hiçbir yere işaret etmiyor " diye katılmıyorum. Boş işaretçiler hiçbir yere işaret etmez, boş değerlere işaret ederler.
TheRealChx101

2
@ TheRealChx101 Boş bir işaretçi ve boş bir değere işaretçi farklı şeylerdir - boş bir işaretçi boş değere işaret etmez. Bir işaretçiye işaretçiniz olduğunu varsayın: işaretçi A işaretçi B'yi işaret eder ve işaretçi B boştur. Bu durumda, A işaretçisi boş bir değeri gösterir ve B işaretçisi boş bir işarettir.
MrZebra

321

Nasıl olduğunu ve nasıl düzeltileceğini açıklamak için birçok açıklama zaten var, ancak önlemek için en iyi uygulamaları da takip etmelisiniz.NullPointerException s'yi .

Ayrıca bakınız: En iyi uygulamaların iyi bir listesi

Çok önemli bir şekilde, finaldeğiştiriciyi iyi bir şekilde kullanacağımı ekledim. Java'da uygulanabilir olduğunda "son" değiştiriciyi kullanma

Özet:

  1. Kullan finalİyi başlatmayı zorunlu kılmak değiştiriciyi .
  2. Yöntemlerde null döndürmekten kaçının, örneğin, uygulanabilir olduğunda boş koleksiyonlar döndürmekten kaçının.
  3. Ek açıklamaları kullanın @NotNullve@Nullable
  4. Hızlı başarısız olun ve boş nesnelerin boş olmamak durumunda tüm uygulama boyunca yayılmasını önlemek için ekleri kullanın.
  5. Önce bilinen bir nesneye eşittir: if("knownObject".equals(unknownObject)
  6. tercih valueOf()üzerindetoString() .
  7. Boş güvenli StringUtilsyöntemler kullanınStringUtils.isEmpty(null) .
  8. Yöntemlerde dönüş değeri olarak Java 8 İsteğe Bağlı kullanın, İsteğe bağlı sınıf, boş başvurular yerine isteğe bağlı değerleri temsil etmek için bir çözüm sağlar.

4
J2ee projelerinde, Nullpointer istisnası çok yaygındır.Bazı durumlarda referans değişkenleri null değerlere sahiptir.Bu nedenle değişken başlatmayı düzgün bir şekilde kontrol etmelisiniz. = 0) {bayrak kullanan ur kodu}
Amaresh Pattanayak

14
Bazı IDE'lerin (örneğin Eclipse) özelleştirilebilir ek açıklamalara (örn @Nullable. Yukarıda listelendiği gibi) dayalı otomatik iptal analizleri sunduğunu ve potansiyel hatalar hakkında uyarıldığını belirtmek gerekir . Mevcut kod yapısına dayanarak bu tür ek açıklamaları (örn. IntelliJ bunu yapabilir) çıkarmak ve oluşturmak da mümkündür.
Jan Chimiak

4
Yapılması gereken ilk şey null olabilecek bir nesneyi kullanmadan önce, null olup olmadığını kontrol etmelisiniz if (obj==null). Null ise, bu durumda da işlemek için kod yazmalısınız.
Lakmal Vithanage

4
IMO, mümkün olduğunda yöntemlerde null nesnelerin döndürülmesini önlemek ve koddaki byif (obj == null) ´ miktarını azaltmak ve kod okunabilirliği.
LG

4
Bunu okuyun ... bu "en iyi uygulamaları" gerçeği kabul etmeden önce: satisfice.com/blog/archives/27
Stephen C

316

Java'da her şey (ilkel türler hariç) bir sınıf şeklindedir.

Herhangi bir nesneyi kullanmak istiyorsanız iki aşama vardır:

  1. Bildirmek
  2. Başlatma

Misal:

  • Beyan: Object object;
  • Başlatma: object = new Object();

Dizi konsepti için aynı:

  • Beyan: Item item[] = new Item[5];
  • Başlatma: item[0] = new Item();

Başlatma bölümünü vermiyorsanız, NullPointerExceptionortaya çıkar.


3
NullPointerException genellikle bir örneğin yöntemini çağırırken oluşur.Örneğin, bir başvuru bildirir ancak herhangi bir örneği göstermezseniz, yöntemini çağırdığınızda NullPointerException gerçekleşir. örneğin: YourClass ref = null; // veya ref = anotherRef; // ancak anotherRef, ref.someMethod () örneğini işaret etmemiştir; // NullPointerException özel durumunu atacaktır. Genellikle bu şekilde düzeltin: Yöntem çağrılmadan önce, başvurunun boş olup olmadığını belirleyin. örneğin: if (yourRef! = null) {yourRef.someMethod (); }
sunhang

2
Veya istisna yakalama kullanın: örneğin: try {yourRef.someMethod (); } catch (NullPointerException e) {// TODO}
sunhang


315

Boş işaretçi istisnası, bir nesneyi başlatmadan kullandığınızın bir göstergesidir.

Örneğin, onu kodumuzda kullanacak bir öğrenci sınıfı aşağıdadır.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Aşağıdaki kod size bir boş gösterici istisnası verir.

public class School {

    Student student;

    public School() {
        try {
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

Çünkü kullanıyorsunuz student, ancak aşağıda gösterilen doğru kodda olduğu gibi başlatmayı unuttunuz:

public class School {

    Student student;

    public School() {
        try {
            student = new Student();
            student.setId(12);
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

7
Bu güzel bir örnek olsa da, diğer tüm cevaplar tarafından kapsanmayan soruya neler eklediğini sorabilir miyim?
Gizemli

13
Burada "başlatılmamış" kelimesini kullanmak uygun değildir. Gösterdiğiniz örnek aslında "başlatıldı" ve null ile başlatıldı. Başlatılmamış değişkenler için derleyici size şikayet edecektir.
Adrian Shum

2
NPE , başlatılmamış bir alan kullandığınızın bir göstergesi olabilir . Başka şeyler yaptığınızın bir göstergesi olabilir. Bunun gibi tek bir nedenden daha fazla basitleştirmek birinin NPE problemlerini çözmesine yardımcı olmaz ... asıl neden bu değilse.
Stephen C

309

In Java Gümrüğe bütün değişkenler nesneler (veya ilkel) için "referanslar" ve aslında kendileri nesnelerdir.

Bir nesne yöntemini yürütmeye çalıştığınızda başvuru, yaşayan nesneden bu yöntemi yürütmesini ister. Ancak, başvuru NULL değerine başvuruyorsa (hiçbir şey, sıfır, geçersiz, nada), yöntemin yürütülmesinin bir yolu yoktur. Sonra çalışma zamanı bir NullPointerException atarak bunu size bildirir.

Referansınız "null" u işaret ediyor, dolayısıyla "Null -> Pointer".

Nesne VM bellek alanında yaşıyor ve ona erişmenin tek yolu thisreferanslar kullanmak . Bu örneği ele alalım:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

Ve kodunuzdaki başka bir yerde:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Bu, bilinmesi gereken önemli bir şeydir - bir nesneye daha fazla referans olmadığında (yukarıdaki örnekte ne zaman referenceve otherReferenceher ikisi de null değerine işaret ettiğinde ), nesne "ulaşılamaz" dır. Onunla çalışmanın hiçbir yolu yoktur, bu nedenle bu nesne çöp toplanmaya hazırdır ve bir noktada VM, bu nesne tarafından kullanılan belleği serbest bırakır ve başka bir nesne tahsis eder.


280

Bir NullPointerExceptionnesne nesnesinin bir dizisini bildirdikten sonra derhal içindeki öğelerin kayıttan çıkarılması çalıştığında başka bir oluşum oluşur.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

Karşılaştırma sırası tersine çevrilirse bu özel NPE'den kaçınılabilir; yani, kullanın.equals garantili boş olmayan bir nesne üzerinde .

Bir dizinin içindeki tüm öğeler ortak başlangıç ​​değerlerine sıfırlanır ; herhangi bir nesne dizisi türü için bu, tüm öğelerinnull .

Sen gerekir dizideki öğeleri başlatmak önce erişen veya bunları dereferencing.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

örnek düzeyinde başlatılmamış bir nesnede (sınıf düzeyinde değil) işlem NullPointerException özelliğine yol açar. işlemin örneğe özel olması gerekir. işlem sınıf düzeyinde ise, başlatılmamış nesnede statik bir yöntem çağrıldığında NullPointerException istisnası atmaz. İlkel sarmalayıcı sınıfı nesneleri bile NullPointerException özel durumunu oluşturur.
Shailendra Singh

1. NullPointerException bir RuntimeException, yani program çalışırken görünecek, derleme zamanında olmayacak demektir.! :(, ancak IDE'nin çoğu bunu keşfetmenize yardımcı olur. 2. Atama ifadelerinde 'null' anahtar kelimesinin kullanımını en aza indirin. :) Referans url:
tomj0101

@ tomj0101 Bu yorumu neden yaptığınıza dair net değilim ... Ama ikinci noktanıza, daha önce bir örnek Optionalnull değerini döndürmekti. Anahtar kelime iyi. Buna karşı nasıl korunacağını bilmek çok önemlidir. Bu, onun ortak bir oluşumunu ve hafifletmenin yollarını sunar.
Makoto

NullPointerException, yakalamak için önerilmeyen, ancak bunun yerine kaçınan bir çalışma zamanı istisnasıdır.
Shomu

2
@Shomu: Hangi noktada yakalanması gerektiğini bile önerebilirim?
Makoto
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.