Обновить
5
0
Олег Петров@WelcomeToRussia

Tech Lead

Отправить сообщение

Мне показалось излишне строгим предложение никогда не возвращать null из методов.

Допустим нам необходимо получить книгу getBook(String id) и получить количество страниц book.getTotalPages().

Рассмотрим 3 случая

Nullable

//Реализация метода:
@Nullable
Book getBook(String id) {
    Book book = // ищем где то книгу, если не найдем вернется null
    return book;  
}

//Реализация получения количества страниц,
//которая может привести к NullPointerException:
totalPages = getBook("Clean code").getTotalPages()  

//Если обратить внимание на подсветку от среды разработки
// или на алерты от статического анализа
// или заглянуть в описание метода,
// то пишем безопасный код:
int totalPages = 0;
Book book = getBook("Clean code");
if (book != null) {
  totalPages = book.getTotalPages()
}

Optional

//Реализация метода:
Optional<Book> getBook(String id) {
    Book book = // ищем где то книгу, если не найдем вернется null
    return Optional.ofNullable(book);  
}

//Нативная реализация получения количества страниц,
//которая вынуждает работать безопасно:
totalPages = getBook("Clean code")
  .map(book -> book.getTotalPages())
  .orElse(0)

Null-object

class Book {
  public static Book emptyBook() {
    return //создаем пустую книгу, без страниц
      // getTotalPages() будет возвращать 0
  }
}

//Реализация метода:
@Nonnull
Book getBook(String id) {
    Book book = // ищем где то книгу, если не найдем вернется null
    if (book == null) {
      return Book.emptyBook();
    } else {
      return book;
    }  
}

//Реализация получения количества страниц,
//которая работает безопасно:
totalPages = getBook("Clean code");

Итого при реализации getBook

с Nullable мы даем возможность ошибиться разработчику при его использовании

с Optional мы обязываем обработать отсутствие значение

с Null-object мы снимаем с разработчика дополнительную логику и реализовываем сами

Не нужно вам возвращать null из метода, уж поверьте. Не мне так популярным фреймворкам, где это применяют.

то в каком-то интерфейсе вашего продукта у вас всплывет фейковый друг с именем "Unknown" и кнопкой "Отправить письмо", которая ничего не делает.

Это вопрос требований и реализации логики. Где то уместно вывести имя "Unknown" и ничего не делать при "Отправить письмо" , а где то - нет.

Правило "всегда использовать использовать аннотации @Nullableтам, где может прилететь null"

Есть разные инструменты работы с nullable объектами, каждый инструмент подходит под свою задачу. О них подробнее напишу в следующей статье.

Nullable подойдет, чтобы пометить поле в объекте.

Optional и null-object подойдут для того, чтобы возвратить значение из метода.

Nullable работает только в compile time.

Optional и null-object работают в runtime.

Null-object не нужно проверять на то, что он "пустой". С ним работают так же как с обычным классом, но у него поведение "пустоты".

Только этот NULL_VALUE надо еще для каждого класса задефайнить и где-то в глобальной переменной держать.

Конечно для каждого класса нужно описать Null-object, но это часть логики. Не во всех задачах подойдет такое решение.

А null из коробки есть.

null - есть и коробки, но его появление, как правило становиться неожиданностью, если не использовать аннотации или Optional.

А чем Null-Object удобнее в обработке, чем простой null? Если каждый раз писать проверку вида

Далее приведу простые примеры реализации null-object, которые дадут понять, что не нужно писать проверки:

строка содержащая что то:

String someString = "I'm not empty";

И пустая строка, которая по сути null-object:

String nullObjectString = "";

И с someString и nullObjectString работать можно не думая о проверке на null.

Более сложный пример с пользовательским классом:

interface Friend {
    void sendEmail();
    String getName();
}

class BestFriend extends Friend {
    private final String name = "m_chrom";
    public void sendEmail() {
         // send email
   }

    public String getName() {
         return name;
    }
}

class NullFriend extends Friend {
    private static final String name = 'Unknown';
    public void sendEmail() {
        //do nothing
    }

    String getName() {
        return name;
    }
}

Согласен.

Есть еще способ - это default или null object.

Пример реализации null object можно подглядеть в jackson: https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/node/NullNode.html

Поле в объекте может быть null и это может быть валидное значение.

Но при этом getter поля может возвратить Optional или Null\Default object.

Например,

class .. {
  private String name;

  public Optional<String> getName() {
    return Optional.ofNullable(name);
  }
}

или

class .. {
  private static final String DEFAULT_NAME = 'UNKNOWN';
  private String name;

  public String getName() {
    return name == null ? DEFAULT_NAME : name;
  }
}

Не вспомню случая, когда возвратить из метода null значение - это было бы хорошо. Разве что для обратной совместимости или при использовании библиотек, где возвращение null - это часть контракта

Все зависит от реализуемой логики. Явные проверки необходимы, если объект nullable и это ожидаемое поведение. Вы привели только лишь один случай, когда null - это ошибка:

  1. Если name не должен быть null и это ошибка, то несомнено нужно бросить исключение, но читаемое и понятное.

if (name != null) {
    return name.length();
} else {
    throw new ViolationException('Expected non-null value on field [name].');
}

А вот несколько примеров, когда null - это ожидаемое значение

private static int DEFAULT_LENGTH = 10;
..
if (name != null) {
    return name.length();
} else {
    return DEFAULT_LENGTH;
}
if (name != null) { 
  return Optional.of(name.length()); 
} else { 
  return Optional.empty(); 
}

Статья всё же не про "Используем конференции для влияния на IT в России". Возникает вопрос в конце статьи, как использовать то?

Понравилась мысль про "снижении степени неопределенности и неизвестности". Это то, чем в принципе занимаются зрелые специалисты в ИТ, по крайней мере, я в это верю.

Часто на конференция делятся кейсами, которые не работают для других. Лучшие практики это все таки результат работы коммьюнити и переработки тонны материалов.

Жаль, что всё по верхам, философия в основном.

Информация

В рейтинге
Не участвует
Откуда
Уфа, Башкортостан(Башкирия), Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Бэкенд разработчик, Delivery Manager
Ведущий
Java
Kotlin
Микросервисная архитектура
Spring Boot
Java Spring Framework