Menu

Java NullPointerException: Nedenleri ve Nasıl Düzeltilir

Java'da bir NullPointerException'ın gerçekte ne anlama geldiği, onu tetiklemenin yaygın yolları, mesajın nasıl okunacağı ve onu önleyen kalıplar.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Java'nın En Yaygın Hatası

Bir NullPointerException (herkes ona NPE der), hiçbir şeye -null'a- işaret eden bir referansı gerçek bir nesneye işaret ediyormuş gibi kullanmaya çalıştığınızda oluşur. Nesne türündeki Java değişkenleri ya bir nesne tutar ya da "burada nesne yok" değeri olan null'ı tutar. null'dan bir şey yapmasını istediğiniz anda -üzerinde bir metot çağırmak, alanlarından birini okumak, içine indekslemek- üzerinde işlem yapılacak hiçbir şey olmadığından JVM hata fırlatır.

Bir önceki sayfada beklenen hataları ele almak için başvurduğunuz try-catch'in aksine, bir NPE neredeyse her zaman sıradan bir programlama hatasıdır. Bu sayfanın amacı onları yakalamak değil, neden olduklarını anlamak ve onları üretmeyen kod yazmaktır.

length()'in üzerinde çalışabileceği bir String yok, bu yüzden program bir NullPointerException ile durur.

Mesajı Okumak

Java 14'ten beri mesaj size tam olarak neyin null olduğunu söyler - buna Helpful NullPointerException (Yardımcı NPE) denir. Herhangi bir şeyi değiştirmeden önce onu okuyun:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
	at Main.main(Main.java:4)

İki parça önemlidir. Cannot invoke "String.length()" başarısız olan işlemdir ve because "name" is null suçluyu adlandırır. at Main.main(Main.java:4) satırı tam satırı gösteren yığın izidir (stack trace). Dolayısıyla çözüm "4. satırı bir try içine sarmak" değil, "4. satırda name'in neden null olduğunu bulmaktır". Hata neredeyse her zaman daha öncede, değerin atanması gerektiği ama atanmadığı bir yerdedir.

Onu Tetiklemenin Yolları

NPE'ler, hepsi "null'a dokunmak"ın çeşitlemeleri olan bir avuç işlemden gelir:

Map aramaları klasik bir kaynaktır: anahtar yoksa get null döndürür ve NPE genellikle o değeri sonunda kullandığınızda, satırlarca sonra ortaya çıkar. Unboxing sinsi olanıdır - null bir Integer'ı bir int'e atamak hata fırlatır, çünkü kopyalanacak bir sayı yoktur.

Bir Null Kontrolü ile Korunmak

En basit savunma, bir referansı kullanmadan önce null olmadığını doğrulayan bir if'tir:

Bir değişkeni sabit bir String ile karşılaştırırken sabiti başa koyun - answer.equals("yes") yerine "yes".equals(answer). Eğer answer null ise, ilk biçim sakince false döndürür, ikincisi ise hata fırlatır.

Objects.requireNonNull ile Hızlı Başarısız Olun

null kontrollerini her yere saçmak gürültülü hale gelir. Bir değer asla null olmamalıysa -bir kurucu (constructor) argümanı gibi- onu sınırda Objects.requireNonNull ile doğrulayın. Bu, kötü değerin geldiği noktada, daha sonra kodunuzun derinliklerinde değil, anında ve net bir mesajla hata fırlatır:

Bu "hızlı başarısız olma" alışkanlığı, 200 satır ötedeki belirsiz bir NPE'yi kaynağında kesin bir şikâyete dönüştürür. Burada istisnayı yakalamak yalnızca mesajı göstermek içindir - gerçek kodda, hatanın düzeltilmesi için onun ortaya çıkmasına izin verirdiniz.

Null'lardan Baştan Kaçınmak

En iyi NPE, ulaşılacak hiçbir null olmadığı için asla gerçekleşemeyendir. Birkaç alışkanlık çok işe yarar:

  • null yerine boş bir koleksiyon ya da dize döndürün. Collections.emptyList() ve "" üzerinde döngü kurmak ve metot çağırmak güvenlidir.
  • Başarısız bir aramanın null yerine gerçek bir değer üretmesi için map'lerde getOrDefault kullanın.
  • Alanları "sonraya" kadar null bırakmak yerine, bildirirken ilk değerlerini atayın.

Bir değer gerçekten isteğe bağlı olduğunda -meşru biçimde hiçbir şey bulamayabilecek bir arama- Java, Optional sunar; bu, çağıranı sessizce bir null geri vermek yerine "yok" durumunu ele almaya zorlayan bir kapsayıcıdır. API'lerinizdeki bu boşlukları tamamen tasarımdan çıkarmak isterseniz, sırada okunacak ilgili kavram budur.

Toparlarsak

Bir NullPointerException, Java'nın size null tutan bir referansı bir nesne tutuyormuş gibi kullandığınızı söylemesidir. Çözüm nadiren onu yakalamaktır - çözüm, yardımcı mesajı okumak, değerin atanması gereken yere kadar geri izlemek ve ya null olmadığını garanti etmek ya da onu kullandığınız noktayı korumaktır. Sınırlarda hızlı başarısız olmak için Objects.requireNonNull'a yaslanın, null yerine boş değerleri ve getOrDefault'u tercih edin ve yokluk gerçek, beklenen bir sonuç olduğunda Optional'a başvurun. Bu zihniyeti kavradığınızda, Java'nın en yaygın hatası kendi kodunuzda en nadirlerinden biri haline gelir.

Sıkça Sorulan Sorular

Java'da NullPointerException'a ne sebep olur?

Bir referansı, gerçek bir nesneye işaret ediyormuş gibi null'a işaret ederken kullandığınızda olur - örneğin bir metot çağırmak (name.length()), bir alan okumak, bir dizi elemanına erişmek veya null bir Integer'ı kutudan çıkarmak (unboxing). Değişken hiçbir nesne tutmaz, dolayısıyla üzerinde işlem yapılacak bir şey yoktur ve JVM bir NullPointerException fırlatır.

Java'da bir NullPointerException nasıl düzeltilir?

Mesajı okuyun - Java 14'ten beri tam olarak neyin null olduğunu belirtir (ör. "Cannot invoke "String.length()" because "name" is null"). Sonra o değişkenin neden null olduğunu izleyin: eksik bir ilk değer atama, null döndüren bir metot ya da bir şey bulamayan bir map araması. Değerin asla null olmaması için kaynağı düzeltin veya kullanımı bir null kontrolü, Objects.requireNonNull ya da Optional ile koruyun.

null kontrolü yapmak mı yoksa NullPointerException yakalamak mı daha iyidir?

null kontrolü yapın. Bir NullPointerException, beklenen bir durumu değil, mantığınızdaki bir hatayı işaret eder; bu yüzden onu yakalamak yerine önlemelisiniz. Onu yakalamak gerçek sorunun nerede olduğunu gizler. try/catch'i G/Ç hataları gibi gerçekten istisnai durumlar için saklayın.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA