koddla

Yazılımcıları bilgi ile güçlendirir.

NullPointerException Nedir?

Bu yazıda Null Pointer Exception (java.lang.NullPointerException)’ın ne olduğuna ve hangi durumlarda karşılaştığımıza bakacağız.

Java’da iki kapsayıcı değişken türü bulunur:

  1. İlkel değişkenler (primitives): veri içeren değişkenlerdir. Bir ilkel değişkendeki verileri değiştirmek isterseniz, bu değişkeni doğrudan değiştirebilirsiniz. Geleneksel olarak ilkel tipler küçük harfle başlar. Örneğin int veya char türündeki değişkenler ilkeldir.
  2. Referanslar: Bir Nesnenin bellek adresini içeren değişkenler, yani bir Nesneye atıfta bulunan değişkenler. Bir referans değişkeninin referans verdiği Nesneyi değiştirmek istiyorsanız, bu değişkenin referansını kaldırmanız gerekir. Dereferanslama genellikle bir metoda veya alana erişmek için . veya bir diziyi indekslemek için [ kullanılmasını gerektirir. Geleneksel olarak referans tipleri genellikle büyük harfle başlayan bir tiple gösterilir. Örneğin Object türündeki değişkenler referanstır.

Primitive int türünde bir değişken oluşturduğunuzu ancak bir değer atamadığınızı düşünün:

int x;
int y = x + x;

Bu iki satır programı çökertecektir çünkü x için bir değer belirtilmemiştir ve y’yi belirtmek için x’in değerini kullanmaya çalışıyoruz. Tüm ilkeller, manipüle edilmeden önce kullanılabilir bir değere atanmalıdır.

Şimdi işlerin ilginçleştiği yer burası. Referans değişkenleri null olarak ayarlanabilir, bu da “hiçbir şeye referans vermiyorum” anlamına gelir. Değişkeni açıkça bu şekilde ayarlarsanız veya bir referans değişkeni tanımlanmamışsa ve derleyici bunu yakalamazsa (Java değişkeni otomatik olarak null olarak ayarlayacaktır), bir referans değişkeninde null değer elde edebilirsiniz.

Bir referans değişkeni sizin tarafınızdan açıkça ya da Java tarafından otomatik olarak null olarak ayarlanırsa ve bu değişkenin referansını kaldırmaya çalışırsanız (dereferans) bir NullPointerException alırsınız.

NullPointerException (NPE) genellikle bir değişken bildirdiğinizde ancak değişkenin içeriğini kullanmaya çalışmadan önce bir nesne oluşturup değişkene atamadığınızda ortaya çıkar. Yani aslında var olmayan bir şeye referansınız vardır.

Aşağıdaki kodu ele alalım:

Integer num;
num = new Integer(10);

İlk satır num adında bir değişken bildirir, ancak aslında henüz bir referans değeri içermez. Henüz neyi işaret edeceğini söylemediğiniz için Java bunu null olarak ayarlar.

İkinci satırda, new anahtar sözcüğü Integer türünde bir nesneyi örneklemek (veya oluşturmak) için kullanılır ve num referans değişkeni bu Integer nesnesine atanır.

Nesneyi oluşturmadan önce num referansını kaldırmaya çalışırsanız bir NullPointerException alırsınız. En önemsiz durumlarda, derleyici sorunu yakalar ve size “num başlatılmamış olabilir” diye bildirir, ancak bazen nesneyi doğrudan oluşturmayan kod yazabilirsiniz.

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

public void doSomething(SomeObject obj) {
   // obj'ye bir şey yapın, obj'nin null olmadığını varsayar
   obj.myMethod();
}

Bu durumda, obj nesnesini oluşturmuyorsunuz, bunun yerine doSomething() yöntemi çağrılmadan önce oluşturulduğunu varsayıyorsunuz. Yöntemi şu şekilde çağırabileceğimizi düşünün;

doSomething(null);

Bu durumda, obj null’dur ve obj.myMethod() ifadesi bir NullPointerException fırlatacaktır.

Yukarıdaki yöntemde olduğu gibi, yöntemin aktarılan nesneye bir şey yapması amaçlanıyorsa, bu bir programcı hatası olduğundan ve programcının hata ayıklama amacıyla bu bilgiye ihtiyacı olacağından NullPointerException fırlatılması uygundur.

Yöntemin mantığının bir sonucu olarak atılan NullPointerExceptions’a ek olarak, bir yöntemin başına aşağıdaki gibi bir şey ekleyerek yöntem argümanlarında null değerler olup olmadığını kontrol edebilir ve NPE’leri açıkça fırlatabilirsiniz:

// Eğer obj null ise özel bir hata mesajı ile bir NPE fırlatır
Objects.requireNonNull(obj, "obj must not be null");

Hata mesajınızda hangi nesnenin null olamayacağını açıkça belirtmenin yararlı olduğunu unutmayın. Bunu doğrulamanın avantajı şudur: 1) kendinize daha net hata mesajları döndürebilirsiniz ve 2) yöntemin geri kalanı için obj yeniden atanmadığı sürece null olmadığını ve güvenli bir şekilde referansının kaldırılabileceğini bilirsiniz.

Alternatif olarak, yöntemin amacının yalnızca aktarılan nesne üzerinde işlem yapmak olmadığı ve bu nedenle null parametrenin kabul edilebilir olabileceği durumlar olabilir. Bu durumda, null parametre olup olmadığını kontrol etmeniz ve farklı davranmanız gerekir. Bunu belgelerde de açıklamanız gerekir. Örneğin, doSomething() şu şekilde yazılabilir:

/**
  * @param obj ____ için isteğe bağlı bir foo. Null olabilir, bu durumda sonuç ____ olacaktır.
  */
public void doSomething(SomeObject obj) {
    if(obj == null) {
       // Bir şeyler yap
    } else {
       // Başka bir şeyler yap
    }
}

Son olarak;

Stack Trace kullanarak Null Pointer Exception nasıl belirlenir

Hata bulma özelliğine sahip sonar NPE’yi tespit edebilir.

Java 14, NullPointerException’ın temel nedenini göstermek için yeni bir dil özelliği ekledi – Aslında bu dil özelliği 2006 yılından beri SAP ticari JVM’nin bir parçasıdır.

Java 14’te, aşağıda örnek bir NullPointerException İstisna mesajı verilmiştir:

“main” iş parçacığında java.lang.NullPointerException: “liste” null olduğu için “java.util.List.size()” çağrılamıyor

NullPointerException oluşmasına neden olan durumlar

Java Dil Spesifikasyonu tarafından doğrudan belirtilen NullPointerException’ın oluştuğu tüm durumlar aşağıda verilmiştir:

  • Null referansın bir örnek alanına erişme (yani alma veya ayarlama). (statik alanlar sayılmaz!)
  • Null referansın bir örnek yöntemini çağırma. (statik yöntemler sayılmaz!)
  • null fırlatma;
  • Null bir dizinin öğelerine erişme.
  • Null üzerinde senkronizasyon – synchronized (someNullReference) { … }
  • Herhangi bir tamsayı/değişken nokta işleci, işlenenlerinden biri kutulu bir null referansı ise bir NullPointerException fırlatabilir
  • Kutulanan değer null ise, kutudan çıkarma dönüşümü bir NullPointerException oluşturur.
  • Null bir referans üzerinde super çağrısı yapmak bir NullPointerException oluşturur. Kafanız karıştıysa, bu nitelikli üst sınıf kurucu çağrılarından bahsediyor:
class Outer {
    class Inner {}
}
class ChildOfInner extends Outer.Inner {
    ChildOfInner(Outer o) { 
        o.super(); // eğer o null ise, NPE atılır
    }
}
  • Bir null koleksiyon/dizi boyunca döngü yapmak için for (eleman : iterable) döngüsü kullanma.
  • switch (foo) { … } (ister ifade ister deyim olsun) foo null olduğunda bir NullPointerException atabilir.
  • foo.new SomeInnerClass(), foo null olduğunda bir NullPointerException oluşturur.
  • name1::name2 veya primaryExpression::name biçimindeki yöntem referansları, name1 veya primaryExpression null olarak değerlendirildiğinde bir NullPointerException fırlatır.JLS’den alınan bir nota göre, someInstance.someStaticMethod() bir NPE fırlatmaz, çünkü someStaticMethod statiktir, ancak someInstance::someStaticMethod yine de bir NPE fırlatır!

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Back to top