Аннотации по JSON и то же, но на русском
@JsonPropertyOrder({"id", name"})
Для классов порядок сериализации полей объекта в JSON
@JsonInclude(JsonInclude. Include .NON_NULL)
не включать параметр если он равен null, можно для всего класса или для конкретного поля
@JsonProperty("<имя_в_json>")
Аннотация ставится над переменной и в json вместо имени переменной попадет указанное в аннотации значение
ALWAYS | всегда включать свойство |
NON_NULL | не включать свойство с нулевым значением |
NON_ABSENT | нет нулевых значений, включая нулевые значения содержимого, такие как Optional, AtomicReference и т. д. |
NON_EMPTY | значения вроде пустых коллекций/карт/массивов/строк и т. д. исключаются (NON_NULL + NON_ABSENT) |
NON_DEFAULT | без значений по умолчанию, например нет примитивов со значениями по умолчанию |
CUSTOM | настраиваемый фильтр для исключения, заданный JsonInclude.valueFilter() |
USE_DEFAULTS | использовать значения по умолчанию либо из уровня класса, либо из уровня ObjectMapper |
Optional.of | возвращает Optional-объект |
Optional.ofNullable | возвращает Optional-объект, а если нет дженерик-объекта, возвращает пустой Optional-объект |
Optional.empty | возвращает пустой Optional-объект |
Optional: Кот Шрёдингера в Java 8
Обычно с Optional работают так:
Это ок, но встроенные методы Optional позволяют обойтись без связки isPresent + get.
Значение по умолчанию: orElse / orElseGet
Вместо сложной конструкции
NO: if (opt.isPresent()) { return opt.get(); } else return "default";
используйте метод orElse:
YES: return opt.orElse("default");
ВАЖНО!!!
Используйте orElse только с константами или простыми операциями, потому что выражение в orElse вычисляется всегда:
BAD: getFromCache(id) .orElse(getFromDB(id);
getFromDB выполнится, даже если getFromCache вернёт результат.
Для тяжёлых операций используйте метод orElseGet:
GOOD: getFromCache(id) .orElseGet(() → getFromDB(id));
Здесь getFromDB выполнится, только если результат getFromCache пустой.
Бросить эксепшн, если результата нет: orElseThrow
return opt.orElseThrow(NotFoundException::new)
В Java 10 появился метод без параметров: opt.orElseThrow()
Если в opt нет значения, код выбросит NoSuchElementException.
Проверка условия: filter
Вместо isPresent + get + проверка условия используйте метод filter:
value.filter(v→v.length()<4) .ifPresent(…)
Преобразования: map / flatMap
Для манипуляций значением Optional используйте метод map:
opt.map(Account::getAddress) .map(String::toUpperCase) .orElse("default");
flatMap используется, если метод отображения возвращает Optional:
Optional<String> getAddress() {…}
opt.flatMap(Account::getAddress);
Методы для Stream API (Java 9)
Когда в стриме один метод возвращает Optional, его часто обрабатывают так:
BAD: .filter(Optional::isPresent) .map(Optional::get)
Метод flatMap пригодится и здесь. Все пустые значения отфильтруются:
GOOD: .flatMap(Optional::stream)
Сравнение Optional
BAD: Обычно делают так: op1.get().equals(op2.get())
Если хотя бы один Optional пустой, будет NullPointerException
GOOD: Сравнивайте Optional напрямую: op1.equals(op2)
Optional — удобный инструмент, который появился в java 8. В документации его цель явно обозначена — возвращаемое значение из метода, когда результата может не быть.
Например, функция поиска может найти нужный элемент, а может и не найти. В этой ситуации отлично подойдёт Optional:
Самые частые ошибки при использовании:
Входные параметры Optional в методах и конструкторах
Класс становится неудобным, приходится добавлять лишние обёртки и подгонять параметры.
BAD: void init(Optional<String> value) {…}
GOOD: Проверяйте параметры на null в начале метода:
void init (String value) {
if (value == null) …
}
Усложнение кода
С появлением Stream API усилился тренд на Fluent API: это когда действия соединяются в одну цепочку. Не создавайте Optional только ради этого, пишите простой код.
BAD: return Optional.ofNullable(value) .orElse("default");
GOOD: return value == null ? "default" : value;
Отложенная обработка Optional
Идеально, если обработка происходит сразу после возвращения из метода:
Optional <String> valueOpt = … ;
String value = valueOpt.orElse("default");
Optional с коллекциями
Возвращайте пустой список, если элементов нет:
BAD: public Optional <List<Integer>> search(…)
GOOD: public List <Integer> search(…)
Работа с примитивами
Для примитивов int, long и double используйте специальные Optional классы:
- OptionalInt
- OptionalDouble
- OptionalLong
Нет затрат на создание объекта, а код становится чуть короче и понятнее. Методов меньше, чем в Optional, но при интенсивной работе с примитивами возможен прирост производительности.
Смотрите видосик (тут только слова)
А также смотрите как с этим бороться (Null safety)
Вопрос: Что будет выведено в консоль?
public class Loader {
public static void main(String[] args) {
B b = new C();
A a = b;
if (a instanceof A) System.out.println("A");
if (a instanceof B) System.out.println("B");
if (a instanceof C) System.out.println("C");
if (a instanceof D) System.out.println("D");
}
}
class A {}
class B extends A {}
class C extends B {}
class D extends C {}
Ответ: A B C
Если непонятно, то читайте про instanceof.
Вопрос: Что будет выведено в консоль?
class SuperBase {
public int i = 3;
public void foo(Object o) {
System.out.println("Object " + i);
}
public void foo(String s) {
System.out.println("String " + i);
}
}
class Base extends SuperBase {
public Base() {
i = 5;
}
public static void main(String[] args) {
SuperBase sb = new Base();
Object o = "";
sb.foo(o);
sb.foo("");
}
}
Ответ: Object 5 String 5
Вопрос: Каким будет результат кода?
class Parent {}
class DeriveOne extends Parent {}
class DeriveTwo extends Parent {}
Parent p = new Parent();
DeriveOne d1 = new DeriveOne();
DeriveTwo d2 = new DeriveTwo();
d1 = (DeriveOne) d2;
Ответ: Ошибка компиляции.
Компилятору сразу понятно, что невозможно кастировать d2 к классу DeriveOne, т.к. d2 не является наследником DeriveOne