Java exception null object reference

Java NullPointerException

Java NullPointerException (NPE) is an unchecked exception and extends RuntimeException . NullPointerException doesn’t force us to use a try-catch block to handle it.

NullPointerException has been very much a nightmare for most Java developers. It usually pop up when we least expect them.

I have also spent a lot of time while looking for reasons and the best approaches to handle null issues. I will be writing here some of the best practices followed industry-wise, sharing some expert talks and my own learning over time.

1. Why NullPointerException Occur in the Code?

NullPointerException is a runtime condition where we try to access or modify an object which has not been initialized yet. It essentially means that the object’s reference variable is not pointing anywhere and refers to nothing or ‘null’.

In the given example, String s has been declared but not initialized. When we try to access it in the next statement s.toString() , we get the NullPointerException.

package com.howtodoinjava.demo.npe; public class SampleNPE < public static void main(String[] args) < String s = null; System.out.println( s.toString() ); // 's' is un-initialized and is null >>

2. Common Places Where NPEs Occur?

Well, NullPointerException can occur anywhere in the code for various reasons but I have prepared a list of the most frequent places based on my experience.

  1. Invoking methods on an object which is not initialized
  2. Parameters passed in a method are null
  3. Calling toString() method on object which is null
  4. Comparing object properties in if block without checking null equality
  5. Incorrect configuration for frameworks like Spring which works on dependency injection
  6. Using synchronized on an object which is null
  7. Chained statements i.e. multiple method calls in a single statement
Читайте также:  Между каким тэгом заключается документ html ответ

This is not an exhaustive list. There are several other places and reasons also. If you can recall any such other, please leave a comment. it will help others also.

3. Best Ways to Avoid NullPointerException

Ternary operator results in the value on the left-hand side if not null else right-hand side is evaluated. It has syntax like :

boolean expression ? value1 : value2;

If the expression is evaluated as true then the entire expression returns value1 otherwise value2.

It is more like an if-else construct but it is more effective and expressive. To prevent NullPointerException (NPE), use this operator like the below code:

String str = (param == null) ? "NA" : param;

3.2. Use Apache Commons StringUtils for String Operations

Apache Commons Lang is a collection of several utility classes for various kinds of operation. One of them is StringUtils.java.

Use the following methods for better handling the strings in your code.

if (StringUtils.isNotEmpty(obj.getvalue()))

3.3. Fail Fast Method Arguments

We should always do the method input validation at the beginning of the method so that the rest of the code does not have to deal with the possibility of incorrect input.

Therefore if someone passes in a null as the method argument, things will break early in the execution lifecycle rather than in some deeper location where the root problem will be rather difficult to identify.

Aiming for fail-fast behavior is a good choice in most situations.

3.4. Consider Primitives instead of Objects

A null problem occurs where object references point to nothing. So it is always safe to use primitives. Consider using primitives as necessary because they do not suffer from null references.

All primitives have some default value assigned to them so be careful.

3.5. Carefully Consider Chained Method Calls

While chained statements are nice to look at in the code, they are not NPE friendly.

A single statement spread over several lines will give you the line number of the first line in the stack trace regardless of where it occurs.

ref.method1().method2().method3().methods4();

These kind of chained statement will print only “NullPointerException occurred in line number xyz”. It really is hard to debug such code. Avoid such calls if possible.

3.6. Use valueOf() in place of toString()

If we have to print the string representation of any object, then consider not using toString() method. This is a very soft target for NPE.

Instead use String.valueOf(object). Even if the object is null in this case, it will not give an exception and will print ‘ null ‘ to the output stream.

3.7. Avoid Returning null from Methods

An awesome tip to avoid NPE is to return empty strings or empty collections rather than null. Java 8 Optionals are a great alternative here.

Do this consistently across your application. You will note that a bucket load of null checks becomes unneeded if you do so.

List data = null; @SuppressWarnings("unchecked") public List getDataDemo() < if(data == null) return Collections.EMPTY_LIST; //Returns unmodifiable list return data; >

Users of the above method, even if they missed the null check, will not see the ugly NPE.

3.8. Discourage Passing of null as Method Arguments

I have seen some method declarations where the method expects two or more parameters. If one parameter is passed as null, then also method works in a different manner. Avoid this.

Instead, we should define two methods; one with a single parameter and the second with two parameters.

Make parameters passing mandatory. This helps a lot when writing application logic inside methods because you are sure that method parameters will not be null; so you don’t put unnecessary assumptions and assertions.

3.9. Call equals() on ‘Safe’ Non-null Stringd

Instead of writing the below code for string comparison

write the above code like given below example. This will not cause in NPE even if param is passed as null.

4. NullPointerException Safe Operations

The instanceof operator is NPE safe. So, instanceof null always returns false .

This operator does not cause a NullPointerException. You can eliminate messy conditional code if you remember this fact.

// Unnecessary code if (data != null && data instanceof InterestingData) < >// Less code. Better!! if (data instanceof InterestingData)

4.2. Accessing static Members of a Class

If you are dealing with static variables or static methods then you won’t get a null pointer exception even if you have your reference variable pointing to null because static variables and method calls are bonded during compile time based on the class name and not associated with the object.

MyObject obj = null; String attrib = obj.staticAttribute; //no NullPointerException because staticAttribute is static variable defined in class MyObject 

Please let me know if you know some more such language constructs which do not fail when null is encountered.

5. What if we must allow NullPointerException in Some Places

Joshua bloch in effective java says that “Arguably, all erroneous method invocations boil down to an illegal argument or illegal state, but other exceptions are standardly used for certain kinds of illegal arguments and states. If a caller passes null in some parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException .”

So if you must allow NullPointerException in some places in your code then make sure you make them more informative than they usually are.

Take a look at the below example:

package com.howtodoinjava.demo.npe; public class SampleNPE < public static void main(String[] args) < // call one method at a time doSomething(null); doSomethingElse(null); >private static String doSomething(final String param) < System.out.println(param.toString()); return "I am done !!"; >private static String doSomethingElse(final String param) < if (param == null) < throw new NullPointerException( " :: Parameter 'param' was null inside method 'doSomething'."); >System.out.println(param.toString()); return "I am done !!"; > >

Output of both method calls is this:

Exception in thread "main" java.lang.NullPointerException at com.howtodoinjava.demo.npe.SampleNPE.doSomething(SampleNPE.java:14) at com.howtodoinjava.demo.npe.SampleNPE.main(SampleNPE.java:8) Exception in thread "main" java.lang.NullPointerException: :: Parameter 'param' was null inside method 'doSomething'. at com.howtodoinjava.demo.npe.SampleNPE.doSomethingElse(SampleNPE.java:21) at com.howtodoinjava.demo.npe.SampleNPE.main(SampleNPE.java:8) 

Clearly, the second stack trace is more informative and makes debugging easy. Use this in the future.

I am done with my experience around NullPointerException. If you know other points around the topic, please share with all of us !!

Источник

Как понять NullPointerException

Эта простая статья скорее для начинающих разработчиков Java, хотя я нередко вижу и опытных коллег, которые беспомощно глядят на stack trace, сообщающий о NullPointerException (сокращённо NPE), и не могут сделать никаких выводов без отладчика. Разумеется, до NPE своё приложение лучше не доводить: вам помогут null-аннотации, валидация входных параметров и другие способы. Но когда пациент уже болен, надо его лечить, а не капать на мозги, что он ходил зимой без шапки.

  1. Его кинули с помощью throw
  2. Кто-то кинул null с помощью throw
  3. Кто-то пытается обратиться по null-ссылке
  1. Вызов нестатического метода класса
  2. Обращение (чтение или запись) к нестатическому полю
  3. Обращение (чтение или запись) к элементу массива
  4. Чтение length у массива
  5. Неявный вызов метода valueOf при анбоксинге (unboxing)
 1: class Data < 2: private String val; 3: public Data(String val) 4: public String getValue() 5: > 6: 7: class Formatter < 8: public static String format(String value) < 9: return value.trim(); 10: >11: > 12: 13: public class TestNPE < 14: public static String handle(Formatter f, Data d) < 15: return f.format(d.getValue()); 16: >17: >
Exception in thread "main" java.lang.NullPointerException at TestNPE.handle(TestNPE.java:15)

В чём причина исключения — в f, d или d.val? Нетрудно заметить, что f в этой строке вообще не читается, так как метод format статический. Конечно, обращаться к статическому методу через экземпляр класса плохо, но такой код встречается (мог, например, появиться после рефакторинга). Так или иначе значение f не может быть причиной исключения. Если бы d был не null, а d.val — null, тогда бы исключение возникло уже внутри метода format (в девятой строчке). Аналогично проблема не могла быть внутри метода getValue, даже если бы он был сложнее. Раз исключение в пятнадцатой строчке, остаётся одна возможная причина: null в параметре d.

 1: class Formatter < 2: public String format(String value) < 3: return "["+value+"]"; 4: >5: > 6: 7: public class TestNPE < 8: public static String handle(Formatter f, String s) < 9: if(s.isEmpty()) < 10: return "(none)"; 11: >12: return f.format(s.trim()); 13: > 14: >
Exception in thread "main" java.lang.NullPointerException at TestNPE.handle(TestNPE.java:12)

Теперь метод format нестатический, и f вполне может быть источником ошибки. Зато s не может быть ни под каким соусом: в девятой строке уже было обращение к s. Если бы s было null, исключение бы случилось в девятой строке. Просмотр логики кода перед исключением довольно часто помогает отбросить некоторые варианты.

С логикой, конечно, надо быть внимательным. Предположим, условие в девятой строчке было бы написано так:

Теперь в самой строчке обращения к полям и методам s нету, а метод equals корректно обрабатывает null, возвращая false, поэтому в таком случае ошибку в двенадцатой строке мог вызвать как f, так и s. Анализируя вышестоящий код, уточняйте в документации или исходниках, как используемые методы и конструкции реагируют на null. Оператор конкатенации строк +, к примеру, никогда не вызывает NPE.

Вот такой код (здесь может играть роль версия Java, я использую Oracle JDK 1.7.0.45):

 1: import java.io.PrintWriter; 2: 3: public class TestNPE < 4: public static void dump(PrintWriter pw, MyObject obj) < 5: pw.print(obj); 6: >7: >
Exception in thread "main" java.lang.NullPointerException at java.io.PrintWriter.write(PrintWriter.java:473) at java.io.PrintWriter.print(PrintWriter.java:617) at TestNPE.dump(TestNPE.java:5)

В параметре pw не может быть null, иначе нам не удалось бы войти в метод print. Возможно, null в obj? Легко проверить, что pw.print(null) выводит строку «null» без всяких исключений. Пойдём с конца. Исключение случилось здесь:

472: public void write(String s)

В строке 473 возможна только одна причина NPE: обращение к методу length строки s. Значит, s содержит null. Как так могло получиться? Поднимемся по стеку выше:

616: public void print(Object obj)

В метод write передаётся результат вызова метода String.valueOf. В каком случае он может вернуть null?

public static String valueOf(Object obj)

Единственный возможный вариант — obj не null, но obj.toString() вернул null. Значит, ошибку надо искать в переопределённом методе toString() нашего объекта MyObject. Заметьте, в stack trace MyObject вообще не фигурировал, но проблема именно там. Такой несложный анализ может сэкономить кучу времени на попытки воспроизвести ситуацию в отладчике.

Не стоит забывать и про коварный автобоксинг. Пусть у нас такой код:

Exception in thread "main" java.lang.NullPointerException at TestNPE.getCount(TestNPE.java:3)

На первый взгляд единственный вариант — это null в параметре obj. Но следует взглянуть на класс MyContainer:

import java.util.List; public class MyContainer < Listelements; public MyContainer(List elements) < this.elements = elements; >public Integer getCount() < return elements == null ? null : elements.size(); >>

Мы видим, что getCount() возвращает Integer, который автоматически превращается в int именно в третьей строке TestNPE.java, а значит, если getCount() вернул null, произойдёт именно такое исключение, которое мы видим. Обнаружив класс, подобный классу MyContainer, посмотрите в истории системы контроля версий, кто его автор, и насыпьте ему крошек под одеяло.

Помните, что если метод принимает параметр int, а вы передаёте Integer null, то анбоксинг случится до вызова метода, поэтому NPE будет указывать на строку с вызовом.

В заключение хочется пожелать пореже запускать отладчик: после некоторой тренировки анализ кода в голове нередко выполняется быстрее, чем воспроизведение трудноуловимой ситуации.

Источник

Оцените статью