Унарный оператор
boolean b = false;
System.out.println(b); // false
System.out.println(!b); // true
int i = -5;
System.out.println(i); // -5
System.out.println(-i); // 5
System.out.println(+i); // -5
int j = 5;
int k = 5;
System.out.println(++j + k++); // 11
System.out.println(j); // 6
System.out.println(k); // 6
Унарный оператор - это оператор, который принимает на вход один аргумент и возвращает некоторое значение.
К унарным операторам относятся: +, -, !
А так же, пре-унарный оператор и пост-унарный оператор.
Varargs (Variable Arguments List)
public static void main(String[] args) {
System.out.println(concat("one", 1, BigDecimal.ONE));
// one,1,1
}
private static String concat(Object... args) {
return Arrays.stream (args)
.map (Object::toString)
.collect(Collectors.joining(","));
}
Varargs (Variable Arguments List, изменяющийся список аргументов) — это способ создания методов, которые могут принимать произвольное количество аргументов одного типа (от нуля и более). Данная возможность появилась в JDK 5.
Запись вида Object... args и есть varargs.
Читать дальшеБесконечные потоки
Stream<Integer> infiniteStream = Stream.iterate(0, i -> i + 2);
List<Integer> intList = infiniteStream
.limit(10)
.collect(Collectors.toList());
// 0, 2, 4, 6, 8, 10, 12, 14, 16, 18
Supplier<UUID> randomUUIDSupplier = UUID::randomUUID;
Stream<UUID> infiniteUUIDStream = Stream.generate(randomUUIDSupplier);
List<UUID> uuidList = infiniteUUIDStream
.skip(10) // пропустить первые 10
.limit(10)
.collect(Collectors.toList());
Интерфейс Stream имеет два статических метода для генерации бесконечных потоков: iterate() и generate().
Читать дальшеStream
Все операции Stream делятся на промежуточные и терминальные и объединяются в потоковые конвейеры.
Потоковый конвейер состоит из источника (например, коллекции, массива, функции-генератора, канала ввода-вывода или генератора бесконечной последовательности) за которым следует ноль или более промежуточных операций и терминальной операции.
Промежуточные операции
📌 Промежуточные операции не выполняются до тех пор, пока не будет вызвана какая-либо терминальная операция.
Они составляют конвейер выполнения Stream. Промежуточную операцию можно добавить в конвейер Stream методами:
filter()
map()
flatMap()
distinct()
sorted()
peek()
limit()
skip()
Защита от повторного запроса с помощью БД
Если вы разрабатываете Веб-приложение или REST-сервис, то рано или поздно столкнётесь с повторными запросами. Что имеется в виду? Объясню на примере Веб-страницы с кнопкой. По нажатию на кнопку, на бэкенд отправляется запрос. Запрос, соответственно, синхронный и пока серверная часть делает какую-то работу, браузер клиента показывает, что загружает страницу. Если это происходит продолжительное время, клиент может подумать, что его запрос завис и нажать кнопку ещё раз. Также повторное нажатие может произойти случайно.
Какая тут может произойти проблема? Если это, например, какой-то запрос данных, то в общем-то проблемы и нет, но если это действие, которое должно отработать только один раз, то тут могут быть весьма неприятные последствия. Для примера в интернет-магазине собрана корзина и создан заказ на оплату (статус REGISTERED), далее по нажатию кнопки "оплатить" с клиента списывают деньги и переводят заказ в статус оплачен (PAID). И если в этом процессе произойдёт двойной запрос, то с клиента могут списать деньги за заказ два раза.
Читать дальшеКомбинирование предикатов
List<String> fruits = List.of("apple", "orange", "pineapple", "grapefruit", "melon");
Predicate<String> isEqualsOrange = Predicate.isEqual("orange");
Predicate<String> isEqualsGrapefruit = Predicate.isEqual("grapefruit");
Predicate<String> isEqualsCitrus = isEqualsOrange.or(isEqualsGrapefruit);
Predicate<String> isNotEqualsCitrus = isEqualsCitrus.negate();
fruits.stream().filter(isEqualsOrange).forEach(System.out::println);
// orange
fruits.stream().filter(isEqualsCitrus).forEach(System.out::println);
// orange grapefruit
fruits.stream().filter(isNotEqualsCitrus).forEach(System.out::println);
// apple pineapple melon
🧩 Predicate - встроенный функциональный интерфейс, добавленный в Java 8 в пакет java.util.function.
Читать дальшеЗапись (record)
public record Point (int x, int y) { }
public static void main(String[] args) {
Point point = new Point(100, 100);
System.out.println(point);
}
// Point[x=100, y=100]
📝 Запись (record) — это класс, объявленный с ключевым словом record вместо ключевого слова class. Запись служит контейнером неизменяемых данных и предназначена для лаконичного описания DTO (Data Transfer Object).
Читать дальшеSentry for Java

Sentry for Java — это программный инструмент, призванный помочь разработчикам отслеживать и управлять ошибками, исключениями и сбоями в приложениях Java.
Читать дальшеDouble braces инициализация
// Double braces initialization
List<String> planets = new ArrayList<>() {{
add("Mercury");
add("Venus");
add("Earth");
add("Mars");
add("Jupiter");
add("Saturn");
add("Uranus");
add("Neptune");
}};
Double braces инициализация - это создание и инициализация объекта в одном java выражении. Чаще всего используется с коллекциями.
На самом деле в этот момент происходит создание анонимного внутреннего класса, расширяющего ArrayList и определение в нём блока инициализации экземпляра.
Читать дальшеStream API
Stream API появился в Java 8 и существенно упростил работу с коллекциями. Теперь можно писать короче и красивее фильтрацию, сортировку и обработку данных.
private final List<Property> properties = getProperties();
/**
* Поиск свойства по имени в списке
* @param propName наименование свойства
* @return найденное свойство или null если не найдено
*/
public Property getPropertyByName(String propName) {
return properties.stream().filter(p -> p.getName().equals(propName)).findFirst().orElse(null);
}
Читать дальше