Поиск по сайту:

Java NullPointerException — обнаружение, исправление и рекомендации


java.lang.NullPointerException — одно из самых популярных веб-приложений Java.

java.lang.NullPointerException

NullPointerException — это исключение времени выполнения, поэтому нам не нужно его перехватывать в программе. NullPointerException возникает в приложении, когда мы пытаемся выполнить какую-либо операцию с нулевым значением, где требуется объект. Некоторые из распространенных причин NullPointerException в программах Java:

  1. Вызов метода для экземпляра объекта, но во время выполнения объект имеет значение null.
  2. Доступ к переменным экземпляра объекта, который во время выполнения имеет значение null.
  3. Выброс нуля в программе
  4. Доступ к индексу или изменение значения индекса массива, который имеет значение null
  5. Проверка длины нулевого массива во время выполнения.

Примеры Java NullPointerException

Давайте рассмотрим несколько примеров NullPointerException в java-программах.

1. NullPointerException при вызове метода экземпляра

public class Temp {

	public static void main(String[] args) {

		Temp t = initT();
		
		t.foo("Hi");
		
	}

	private static Temp initT() {
		return null;
	}

	public void foo(String s) {
		System.out.println(s.toLowerCase());
	}
}

Когда мы запускаем вышеуказанную программу, она выдает следующее сообщение об ошибке NullPointerException.

Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:7)

Мы получаем исключение NullPointerException в операторе t.foo(Hi); , потому что \t здесь равно null.

2. Java NullPointerException при доступе/изменении поля нулевого объекта

public class Temp {

	public int x = 10;
	
	public static void main(String[] args) {

		Temp t = initT();
		
		int i = t.x;
		
	}

	private static Temp initT() {
		return null;
	}

}

Приведенная выше программа выдает следующую трассировку стека NullPointerException.

Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:9)

Исключение NullPointerException возникает в операторе int i=t.x;, потому что \t здесь равно null.

3. Java NullPointerException, когда null передается в аргументе метода

public class Temp {

	public static void main(String[] args) {

		foo(null);

	}

	public static void foo(String s) {
		System.out.println(s.toLowerCase());
	}
}

Это одно из наиболее распространенных случаев возникновения java.lang.NullPointerException, потому что вызывающий объект передает нулевой аргумент.

На изображении ниже показано исключение нулевого указателя, когда указанная выше программа выполняется в Eclipse IDE.

4. java.lang.NullPointerException, когда выдается нуль

public class Temp {

	public static void main(String[] args) {

		throw null;
	}

}

Ниже приведена трассировка стека исключений вышеуказанной программы, показывающая исключение NullPointerException из-за оператора throw null;.

Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:5)

5. NullPointerException при получении длины нулевого массива

public class Temp {

	public static void main(String[] args) {

		int[] data = null;
		
		int len = data.length;
	}

}
Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:7)

6. NullPointerException при доступе к значению индекса нулевого массива

public class Temp {

	public static void main(String[] args) {

		int[] data = null;
		
		int len = data[2];
	}

}
Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:7)

7. NullPointerException при синхронизации с нулевым объектом

public class Temp {

	public static String mutex = null;
	
	public static void main(String[] args) {

		synchronized(mutex) {
			System.out.println("synchronized block");
		}		
	}
}

synchronized(mutex) вызовет исключение NullPointerException, поскольку объект \mutex имеет значение null.

8. Статус HTTP 500 java.lang.NullPointerException

Иногда мы получаем ответ страницы ошибки от веб-приложения Java с сообщением об ошибке «Статус HTTP 500 — внутренняя ошибка сервера» и основной причиной в виде java.lang.NullPointerException.

Для этого я отредактировал пример проекта Spring MVC и изменил метод HomeController, как показано ниже.

@RequestMapping(value = "/user", method = RequestMethod.POST)
	public String user(@Validated User user, Model model) {
		System.out.println("User Page Requested");
		System.out.println("User Name: "+user.getUserName().toLowerCase());
		System.out.println("User ID: "+user.getUserId().toLowerCase());
		model.addAttribute("userName", user.getUserName());
		return "user";
	}

На изображении ниже показано сообщение об ошибке, выдаваемое ответом веб-приложения.

Вот трассировка стека исключений:

HTTP Status 500 – Internal Server Error

Type Exception Report

Message Request processing failed; nested exception is java.lang.NullPointerException

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
	org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
Root Cause

java.lang.NullPointerException
	com.journaldev.spring.controller.HomeController.user(HomeController.java:38)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	java.lang.reflect.Method.invoke(Method.java:498)

Основной причиной является исключение NullPointerException в операторе user.getUserId().toLowerCase(), поскольку user.getUserId() возвращает значение null.

Как обнаружить java.lang.NullPointerException

Обнаружить NullPointerException очень просто, просто посмотрите на трассировку исключения, и она покажет вам имя класса и номер строки исключения. Затем посмотрите на код и посмотрите, что может быть нулевым, вызывая исключение NullPointerException. Просто посмотрите на все приведенные выше примеры, из трассировки стека очень ясно, что вызывает исключение нулевого указателя.

Как исправить исключение NullPointerException

java.lang.NullPointerException – это непроверенное исключение, поэтому нам не нужно его перехватывать. Исключения нулевого указателя можно предотвратить с помощью проверки нулевого значения и методов превентивного кодирования. Посмотрите приведенные ниже примеры кода, показывающие, как избежать java.lang.NullPointerException.

if(mutex ==null) mutex =""; //preventive coding
		
synchronized(mutex) {
	System.out.println("synchronized block");
}
//using null checks
if(user!=null && user.getUserName() !=null) {
System.out.println("User Name: "+user.getUserName().toLowerCase());
}
if(user!=null && user.getUserName() !=null) {
	System.out.println("User ID: "+user.getUserId().toLowerCase());
}

Рекомендации по кодированию, чтобы избежать исключения NullPointerException

1. Давайте рассмотрим приведенную ниже функцию и найдем сценарий, вызывающий исключение нулевого указателя.

public void foo(String s) {
    if(s.equals("Test")) {
	System.out.println("test");
    }
}

NullPointerException может возникнуть, если аргумент передается как null. Тот же метод можно написать, как показано ниже, чтобы избежать исключения NullPointerException.

public void foo(String s) {
	if ("Test".equals(s)) {
		System.out.println("test");
	}
}

2. Мы также можем добавить проверку на null для аргумента и генерировать IllegalArgumentException при необходимости.

public int getArrayLength(Object[] array) {
	
	if(array == null) throw new IllegalArgumentException("array is null");
	
	return array.length;
}

3. Мы можем использовать тернарный оператор, как показано в приведенном ниже примере кода.

String msg = (str == null) ? "" : str.substring(0, str.length()-1);

4. Используйте метод String.valueOf(), а не метод toString(). Например, код метода проверки PrintStream println() определяется, как показано ниже.

public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
        }
    }

В приведенном ниже фрагменте кода показан пример, в котором используется метод valueOf() вместо toString().

Object mutex = null;

//prints null
System.out.println(String.valueOf(mutex));

//will throw java.lang.NullPointerException
System.out.println(mutex.toString());

5. По возможности пишите методы, возвращающие пустые объекты, а не null, например, пустой список, пустую строку и т. д.

6. Есть несколько методов, определенных в классах коллекций, чтобы избежать NullPointerException, вы должны их использовать. Например, contains(), containsKey() и containsValue().

Ссылка: Документ API