Что такое Null Pointer Exception и как его исправить?

207
02 июня 2018, 16:30

Что из себя представляет исключение Null Pointer Exception (java.lang.NullPointerException) и почему оно может происходить?

Какие методы и средства использовать, чтобы определить причину возникновения этого исключения, приводящего к преждевременному прекращению работы приложения?

Перевод вопроса «What is a Null Pointer Exception, and how do I fix it?» @Ziggy.

Answer 1

Когда вы объявляете переменную ссылочного типа, на самом деле вы создаете ссылку на объект данного типа. Рассмотрим следующий код для объявления переменной типа int:

int x;
x = 10;

В этом примере переменная x имеет тип int и Java инициализирует её как 0. Когда вы присвоите переменной значение 10 (вторая строка), это значение сохранится в ячейке памяти, на которую ссылается x.

Но когда вы объявляете ссылочный тип, процесс выглядит иначе. Посмотрим на следующий код:

Integer num;
num = new Integer(10);

В первой строке объявлена переменная num, ее тип не относится к встроенному, следовательно, значением является ссылка (тип этой переменной, Integer, является ссылочным типом). Поскольку вы еще не указали, на что собираетесь ссылаться, Java присвоит переменной значение Null, подразумевая «Я ни на что не ссылаюсь».

Во второй строке, ключевое слово new используется для создания объекта типа Integer. Этот объект имеет адрес в памяти, который присваивается переменной num. Теперь, с помощью переменной num вы можете обратиться к объекту используя оператора разыменования ..

Исключение, о котором вы говорите в вопросе, возникает, если вы объявили переменную, но не создали объект, то есть если вы попытаетесь разыменовать num до того, как создали объект, вы получите NullPointerException. В самом простом случае, компилятор обнаружит проблему и сообщит, что

num may not have been initialized

Что говорит: «возможно, переменная num не инициализирована».

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

public void doSomething(Integer num){
   // Работаем с num
}

В этом случае создание объекта (переменная num) лежит на вызывающем коде, то есть вы предполагаете, что он был создан ранее – до вызова метода doSomething. К сожалению, следующий вызов метода вполне возможен:

doSomething(null);

В этом случае значение переменной num будет null. Лучшим способом избежать данного исключения будет проверка на равенство нулю. Как результат, функция doSomething должна быть переписана следующим образом:

public void doSomething(Integer num){
    if (num != null) {
       // Работаем с num
    }
}

Как альтернативный вариант предыдущему примеру вы можете сообщить вызывающему коду, что метод был вызван с неверными параметрами, например, с помощью IllegalArgumentException.

public void doSomething(Integer num){
    if (num == null)
        throw new IllegalArgumentException("Num не должен быть null"); 
    // Работаем с num
}

Также, обратите внимание на вопрос «Что такое stack trace и как с его помощью находить ошибки при разработке приложений?».

Перевод ответа «What is a Null Pointer Exception, and how do I fix it?» @Vincent Ramdhanie.

Answer 2

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

Типичное решение с проверкой на null

Article article = getFirstJavaArticle();
    if (article == null) {
        article = fetchLatestArticle();
    }

А теперь решение с использованием Optional<T>. Представим что getFirstJavaArticle() возвращает Optional<Article>

getFirstJavaArticle()  
    .orElseGet(this::fetchLatestArticle);

Решение с Optional позволяет нам избежать кода с проверками на null и работать в функциональном стиле. Стоит заметить что Optional не является панацеей от всех бед

Так же для предотвращения NullPointerException используется паттерн NullObject

Абстрактный Entity class

public abstract class AbstractCustomer {
    protected String name;
    public abstract String getName();
}

Реальная реализация

public class RealCustomer extends AbstractCustomer {
   public RealCustomer(String name) {
      this.name = name;     
   }
   @Override
   public String getName() {
      return name;
   }
}

Реализация NullObject

public class NullCustomer extends AbstractCustomer {
   @Override
   public String getName() {
      return "Not Available in Customer Database";
   }
 }

Использование (как пример)

public class CustomerFactory {
   public static final String[] names = {"Rob", "Joe", "Julie"};
   public static AbstractCustomer getCustomer(String name){
      for (int i = 0; i < names.length; i++) {
         if (names[i].equalsIgnoreCase(name)){
            return new RealCustomer(name);
         }
      }
      return new NullCustomer();
   }
}

Вместо возвращения null мы возвращаем экземпляр класс NullCustomer и не падаем с NullPointerException. Но как мне кажется присутствует небольшой Overhead: необходимо создавать иерархию наследования.

Answer 3

Это Exception , который встречается тогда, когда ты ссылаешься на объект, который = null(не инициализирован) или пытаешься вызвать методы/обратиться к переменным объекта, который = null. Решение этой проблемы:

  1. Проверка на null, if(Твой объект==null){//Your code}

  2. try{}catch(NullPointerException e){//Your code}

  3. Когда тебе выбрасывает нулл,то обычно указывает "иерархию строчек"(что, как вызывалось, что привело тебя к нулл). И там ты можешь посмотреть, где у тебя объект не инициализирован, там и можно сразу исправить ошибку.

  4. Может встречаться в массивах/списках, когда вызываешь объект под номер n, при том, что объекта туда предварительно не записан. Вроде, все))

READ ALSO
UDP DatagramPacket извлечь данные в строку

UDP DatagramPacket извлечь данные в строку

В консоль выводятся куча байт, как из modifiedSentence получить строку?

250
Мануал JAVA на русском

Мануал JAVA на русском

Ребята нужна не книга а мануал по JavaЧто то вроде php

284
Простейшая кодировка букв

Простейшая кодировка букв

Пишу прогу, которая принимает строку(только буквы, никаких знаков препинания и цифр) и целое число, насколько передвинуть символы сроки по ASCII таблицеНичего...

218
Как создать SSL соединение к postgresql из Java swing?

Как создать SSL соединение к postgresql из Java swing?

Как создать SSL соединение к postgresql из Java swing?

206