Muhtemelen Java’da karşılaştığınız ilk istisnadır(exception) ve yeni başlayanlar için bir kâbus niteliğindedir kendisi. Yazdığınız kodun kalitesi yüksek olabilir ama bazen gözünüzden kaçan ufak bir kontrol canlı(production) ortamda NullPointerException fırlamasına ve sistemin kırılmasına sebep olabilir. Bu yazımda bunu en aza indirmek için bazı yöntemlerden bahsedeceğim.
NullPointerException Nedir ?
Bildiğiniz gibi, Java, ilkel(primitive) türlere(boolean, int, vb.) ve referans türlerine(Boolean, Integer) ayrılmıştır. Java’daki referans türlerinde , “nesne yok” demenin yolu “null” ‘dır. NullPointerException, null olan referans üzerinden herhangi bir işlem yapmaya çalışıldığında çalışma anında(Runtime) oluşan bir istisnadır. İstisnalar(Exceptions) konusunda yazımı buradan okuyabilirsiniz.
Kaçış Yolları
NullPointerException’ı önlemek için dikkatli ve defansif kodlama yöntemlerini kullanmalısınız. Bahsedeceğimiz yöntemler kod kalitesi ve sağlamlık üzerinde önemli etkiye sahip olan basit yöntemlerdir. Ayrıca sürekli kullanıldığımız != null kontrollerini de büyük ölçüde azaltacaktır. Eğer sizinde kullandığınız yöntemler varsa paylaşabilirseniz sevinirim.
equals() ve equalsIgnoreCase() kullanımına dikkat etmek
Equals() metodu simetrik olduğu için, a.equals(b) ‘yi çağırmak b.equals(a)‘ yı çağırmakla aynıdır ve bu yüzden birçok yeni yazılımcı a ve b nesnelerine dikkat etmemektedir. equals metodunu çağıran nesnenin null olması durumunda NullPointerException fırlayacaktır. Bu sebeple equals metodunu çağıran nesnenin kesinlikle null olmadığından emin olmalısız.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
String str = null; if("koray".equals(str)){ } if(str.equals("koray")){ // Riskli kullanım } if(EnumGunler.PAZARTESI.equals(baskaEnum)){ } |
toString() yerine valueOf() kullanmak
Null referans’ın toString() metodunu çağırdığında NullPointerException’ı fırlayacağından, valueOf () metodunu kullanmak daha iyidir. Özellikle de Integer, Float, Double, BigDecimal gibi referans tipler söz konusu olduğunda kullanılmalıdır. Nesnenin null olup olmadığından emin değilseniz ideal bir yöntemdir.
1 2 |
BigDecimal bd = null; System.out.println(String.valueOf(bd)); |
Güvenli kütüphaneler kullanmak
En yaygın olanlardan biri, Apache’nin StringUtils sınıfıdır. NullPointerException endişesi olmadan StringUtils.isBlank(), isNumeric(), isWhiteSpace() ve diğer yardımcı metotlarını kullanabilirsiniz. Fakat siz yine de javadoc’larını okumayı unutmayın.
1 2 3 4 |
System.out.println(StringUtils.isEmpty(null)); System.out.println(StringUtils.isBlank(null)); System.out.println(StringUtils.isNumeric(null)); System.out.println(StringUtils.isAllUpperCase(null)); |
Collection döndüren metotlarda null yerine boş collection’lar döndürün
Effective Java kitabının ikinci baskısının 43. Maddesinde (Birinci Basımdaki # 27), Joshua Bloch metotların null döndürmeleri yerine boş olarak dönmelerini önerir. Diyelim şirketinizdeki diğer yazılımcıların kullanacağı liste döndürecek şekilde API yazıyorsunuz. Bu API’yı kullanan yazılımcılar her çağırım yaptıklarında null kontrolü yapmak zorundadır. Fakat null değilde, listeyi boş olarak döndürüseniz kullanılan iterasyonlarda veya isEmpty() gibi kontrollerde patlamayacaktır.
1 2 3 4 5 6 7 |
List data = null; public List getData(){ if(data == null) return Collections.EMPTY_LIST; return data; } |
@NotNull ve @Nullable gibi notasyonları kullanın
@Nullable ve @NotNull kendi başına hiçbir şey yapmaz. Dokümantasyon araçları olarak hareket etmektedirler. FindBugs gibi pluginlerin kod analizi yapmasını ve uyarı vermesini sağlar. Ayrıca derleme anında(compile time) IDE’lerde NullPointerException’ın ortaya çıkabileceği kodu işaret eder. Intellij açıklaması için tıklayınız.
1 2 3 |
public void setX(@NotNull Object aX ) { // some code } |
İlkel(primitive) tipleri unutmayın
İlkel tiplerde null olmadığından dolayı olabildiğince özellikle matematiksel işlemlerde ilkel tipleri kullanmaktan yana olun.
Metotların null parametreleri olmamalıdır
İki veya daha fazla parametre bekleyen bir metot olsun. Bu parametrelerden biri null olarak gönderilirse, metot farklı bir şekilde çalışır veya işleyişine göre kırılabilir.
Burada yapılması gerekenler öncelikle kullanılan metot içerisinde parametrelerin null kontrolleri koyulmalı ve metot throws ile işaretlenmelidir veya Lombok kullanıyor iseniz @NonNull notasyonunu kullanınız. Lombok hakkında yazıyı okumak için tıklayınız.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/** * @param x * @param y * @return * @throws NullPointerException */ public Long topla(Long x, Long y) throws NullPointerException { if(x == null || y == null){ throw new NullPointerException("X veya Y parametresi boş olamaz"); } return x + y; } |
Java 8 ile gelen Optional özelliğini kullanın
Bu can sıkıcılığını ortadan kaldırmak için Java 8 ile beraber Optional sınıfı gelmiştir. Optional sınıfını anlatan ayrı bir yazı paylaşmıştım buradan okuyabilirsiniz.
Harikaa olmuşşş
Çok teşekkürler Esra Hanım
Çok işime yaradı. Güzel anlatım olmuş. Devamını bekliyoruz
Bilgilendirmeler için teşekkürler, benim bir best practise sorum var, bir A sınıfından üretilen bir a objesi içerisinde composite B objesi ve onun da içerisinde bir C objesi ve son olarak aynı şekilde bir D objesi olsun.
a. getB().getC().getD() satırında null pointer exception handle edebilmek için tüm objeleri if(a!=null) sonra sırayla b not equal to null vb. kontrolleri yapmak kodu kabalaştırıyor ya da en azından bazen okunması zor uzun kod blokların dönüşebiliyor. Sizin de bahsettiğiniz gibi optional sınıfı belki çözüm ancak tüm sınıfları optional yapmak istemiyorsak ya da null değeri anlamlı olabileceği durumlar varsa ne yapmalıyız? Her ne kadar runtime exceptionlar yakalanmaması gereken durumlar olsa da bu satırı try içerisine alıp, runtime excp yakalarsa ve bir default value dönersek bu bir anti pattern olur mu? Bilgiler için tekrar teşekkür ediyorum.
Merhabalar, böyle bir durumda ben metodlara parçalıyorum. bütün sınıflarda d yi veren getter koyarsın sonra hepsi birbirini çağırır yukarı kadar datayı taşırsın. a.getD() diye çağırım yaparsın. Diğer sorun için Çalışma zamanı istisnaları, bir programlama sorununun doğrudan bir sonucu olan sorunları temsil eder ve bu nedenle yakalanmamalıdır.