Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
А вы используете эту поговорку так, как будто девелоперы даже не слышали обо всем этом.
Методы не должны возвращать значения, требующие особой обработки. Пользователи будут забывать о проверках. Например, возвращай пустой массив или список, а не null.
Optional<SingletonClass>Optional? Подключить ГуавуOptional значение без проверки не извлечь. Это защитит от «забывания» на этапе компиляции. На самом деле, даже на уровне IDE.get(), и не проверять все остальные случаи — проверки на это на этапе компиляции нет.Nullable<T> (схожий по поведению, но иной по задаче класс в C#) через .Value, без проверки, всегда.Это защитит от «забывания» на этапе компиляции. На самом деле, даже на уровне IDE.
Optional: IDE вполне понимают аннотацию @javax.annotation.Nullable на методах.2. Может это и можно, но я не нашел как и IDEA настроить чтобы отсутствие аннотации было равносильно NotNull, а не @Nullable. А в таком случае, ставить аннотацию практически везде банально лень.
@ParametersAreNonnullByDefault. IDEA умеет его понимать начиная с 13-й версии. Данную аннотацию можно навесить на пакет, а не только на класс.3. Функциональный тип Optional и работа с ним, как с монадой, для Java-программиста очень непривычна и вызывает отторжение.Согласен. Оно выглядит инородно, на самом деле пользы дает мало и с учетом
@Nullable — не нужно.Скажем так, лично я это решение люблю за его простоту и по-возможности использую.
null?А если результат — это единичный экземпляр класса?
объект класса может нормально функционировать даже в том случае, если он isNull.
Мое решение работает для всех языков, где есть функции, классы и тип bool. Как с ограничениями в виде статической типизации, так и без.
Вот предположим, у вас объект — это запись с сотрудником, какой у нее идентификатор?
return id==null_id;PS Вообще, это паттерн Null Object, со всеми его недостатками.
Например, null_id.
isNull, передаст этот идентификатор дальше?А вот если со статической, то Null Object неплохо работает.
Да и у Вас в исходном вопросе было ограничение, что результат — именно объект некоего класса.
когда есть полностью корректный экземпляр «отсутствующих» данных
Во многих современных языках null — это (отсутствующий) экземпляр определенного класса.
При этом Вы, как разработчик класса, можете это обеспечить
Во многих — но не во всех. И это при проектировании API нужно учитывать.
введенному вами же правилу
API проектируется для использования в конкретном языке (или конкретной технологии)
Это правило ввел не я — так работает БД. Что и позволяет мне в своем коде использовать диапазон <0 под свои корыстные нужды.
А если Вы хотите обеспечить максимально возможный охват языков и платформ, базовая часть API должна быть максимально универсальной.
Что случится, если кто-то передаст в БД идентификатор -1?
Не хочу.
Что значит «кто-то»? Сериализацию объекта в БД Вы сами и должны написать. Что бы потом пользователи этим уже не страдали.
Но будьте готовы к тому, что пользователи Вашего API и на null не проверять, и исключения не обработают.
Это же публичный API, пользователи могут использовать возвращенные им объекты, как им угодно.
защитить от неразумного разработчика его же программу — весьма сложно
Именно поэтому и надо сделать сериализацию за пользователя.
null даст ошибку как можно раньше (т.е., на этапе вызова result.id) + null можно ловить статическим анализом.null даст ошибку как можно раньше
result.id
Null Object выдаст ошибку там, где это будет нужно.
надо от пользователя скрывать (это называется инкапсуляция), чтобы он не имел прямой доступ к полям класса, а использовал соответствующие методы.
Ошибку выдаст не он, а использующий его код.
при попытке доступа к данным этого объекта либо выбрасывается исключение
null?выдаются такие же null объекты, если Вы исключения не используете
Если Вы хотите пример — поясню: Класс Object пишется таким образом
Find репозитория, который ищет сотрудника по заданным параметрам. В отличии от метода Get, метод Find не бросает эксепшн, когда не находит объект. Теперь есть простой сценарий: коду необходимо найти сотрудника по параметрам и уволить его. Программист решил использовать метод Find. Что нам делать дальше?И чем это лучше обычного null?
Намного проще считать, что функция всегда оперирует валидным объектом.
А если результат — это единичный экземпляр класса?
NullObject, чем везде делать двойную проверку.User и NullUser (наследник от User). Есть некий метод getUser(String username).User getUser(String username){
Чего-то тут делаем...
return user;
}
User user = getUser("username");
if (user !=null) {
userId = user.getId();
}else{
LOG.error("user from 'username' not found.");
}class User {
public static final NULL_USER = new NullUser();
public boolean isNull(){ return false;}
...
private class NullUser extend User{
@Override
public boolean isNull(){ return true;}
@Override
public Long getId(){
throw new Exception('get id property from NullUser');
}
}
}User getUser(String username){
// Чего-то тут делаем...
if (user = null) {
user = User.NULL_USER;
LOG.error("not found user from " + username);
}
return user;
}
User user = getUser("username");
userId = user.getId();
// или, когда надо проверку:
if (!user.isNull()) userId = user.getId();
null совместно с аннотациями/контрактами и статическим анализом.private class NullUser extend User{
@Override
public boolean isNull(){ return true;}
@Override
public Long getId(){
throw new Exception('get id property from NullUser');
}
}private class NullUser extend User{
@Override
public boolean isNull(){ return true;}
@Override
public Long getId(){
LOG.error('get id property from NullUser');
return null;
}
}Применяй самые подходящие типы. Например, принимай и передавай IP-адрес как специальный тип, а не число или строку.Ох, как я согласен! Но вот беда: часто бывает, что значение вполне укладывается в примитивный тип (т.е., например, IPv4 адрес эффективнее всего передавать именно что числом), но очевидно, с точки зрения дизайна API — это плохо.
Создание API: в рамку и на стену