10986
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP
🗺 map() vs flatMap(): Битва трансформеров
Оба метода находятся в конвейере (Intermediate operations) и нужны для преобразования данных. Но работают они с разной геометрией.
1️⃣ map() - Один к одному (1:1)
Самый простой случай. Вы берете элемент, делаете с ним что-то и возвращаете один измененный элемент. Структура потока не меняется.
💙Логика:
💙Пример: Есть список сотрудников (Employee), нужно получить список их имен (String).
💙Аналогия: У вас есть коробка с яблоками. Вы берете каждое яблоко, чистите его и кладете обратно. В итоге у вас столько же объектов, просто они изменились.
stream.map(employee -> employee.getName()) // Был Employee, стал String
flatMap() - Один ко многим (1:N) + СплющиваниеDepartment), в каждом отделе - список сотрудников (List<Employee>). Вы хотите получить один общий список всех сотрудников компании.map, у вас будет поток коробочек.flatMap, вы высыпаете конфеты из всех коробочек в одну большую кучу.List<List<String>> nestedList = List.of(List.of("A", "B"), List.of("C", "D"));map:
// Мы получим Stream из Списков: Stream<List<String>>
nestedList.stream()
.map(list -> list.stream())
.toList();
// Результат: [[A, B], [C, D]] — Матрёшка осталась!
flatMap:
// Мы получим единый Stream строк: Stream<String>
nestedList.stream()
.flatMap(list -> list.stream()) // Превращаем каждый список в стрим и сливаем
.toList();
// Результат: [A, B, C, D] — То, что нужно!
map: Используем в 90% случаев. Когда нужно просто превратить А в Б (Число в Строку, Объект в Поле объекта).flatMap: Используем, когда нужно убрать вложенность.List<List<T>> List<T>Order List<LineItem>.map преобразует элементы.flatMap преобразует и разворачивает структуру.
Вопросы-ответы собеседования
Можно ли создать экземпляр абстрактного класса?
Что такое интерфейс?
Как вызвать нестатический метод в статическом?
Чем отличаются параметры от аргументов в методе?
Что такое конструктор? Как его создать и вызвать?
Что такое параметризованный конструктор?
Что такое конструктор по умолчанию?
Что такое приватный конструктор? Зачем он закрытый?
Что такое статическая переменная? Как работает static поле?
Что такое статический метод? Как вызвать static метод?
источник
📲 Мы в MAX
👉@BookJava
🍒 Магия двойного двоеточия: Method References
Мы уже научились писать лямбды. Но иногда даже лямбда кажется слишком громоздкой. Если ваша лямбда не делает ничего, кроме вызова одного уже существующего метода, Java позволяет использовать Method Reference (ссылку на метод).
Синтаксис простой: Класс::метод (без скобок!).
🛠 4 ситуации, когда это работает
Есть 4 основных способа использовать оператор ::. Важно понимать разницу, чтобы не путаться.
1. Ссылка на статический метод
💙 Лямбда: s -> Integer.parseInt(s)
💙 Reference: Integer::parseInt
💙 Суть: Просто перенаправляем входящий параметр в статический метод.
2. Ссылка на метод конкретного объекта
💙 Лямбда: obj -> System.out.println(obj)
💙 Reference: System.out::println
💙 Суть: У нас уже есть готовый объект (System.out), и мы вызываем его метод для каждого элемента.
3. Ссылка на метод произвольного объекта определенного типа (Самый хитрый пункт! 🤯)
💙 Лямбда: s -> s.toLowerCase()
💙 Reference: String::toLowerCase
💙 Суть: Здесь метод вызывается у самого объекта, который пришел в лямбду. Хотя синтаксис похож на статический вызов, это вызов инстанс-метода.
4. Ссылка на конструктор
💙 Лямбда: () -> new ArrayList<>()
💙 Reference: ArrayList::new
💙 Суть: Используется для создания новых объектов (часто в Stream API: Collectors.toCollection(ArrayList::new)).
💻 Пример: Было vs Стало
Смотрите, как очищается код. Допустим, у нас есть список имен:
List<String> names = Arrays.asList("Alex", "Bob", "Anna");
// ❌ Уровень 1: Анонимный класс (Олдскул)
names.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
// ⚠️ Уровень 2: Обычная лямбда
names.forEach(s -> System.out.println(s));
// ✅ Уровень 3: Method Reference (Красота)
names.forEach(System.out::println);
x -> Class.method(x)x -> x.method()::.x -> System.out.println("Name: " + x)), то Method Reference уже не подойдет, оставайтесь на лямбде.
☕ Функциональные интерфейсы: Магия за кулисами Лямбд
Если вы используете лямбды (а вы наверняка их используете), значит, вы работаете с функциональными интерфейсами. Давайте разберем, что это такое, зачем нужна аннотация и какие интерфейсы вы обязаны знать наизусть.
🎯 Что это такое?
Функциональный интерфейс - это интерфейс, который содержит ровно один абстрактный метод.
Именно это ограничение позволяет компилятору превращать лямбда-выражение в экземпляр этого интерфейса.
💙 Примечание: В интерфейсе может быть сколько угодно default или static методов. Главное - только один абстрактный.
📝 Аннотация @FunctionalInterface
Ставить её над интерфейсом не обязательно, но хорошим тоном считается ставить.
Зачем? Она работает как защита от дурака: если вы или ваш коллега случайно добавите второй абстрактный метод в интерфейс, компилятор сразу выдаст ошибку, не дожидаясь падения кода в местах использования лямбд.
🧰 Шпаргалка: "Великолепная четверка"
В пакете java.util.function уже есть готовые интерфейсы на 99% случаев жизни. Не пишите свои велосипеды, пока не выучите эти:
1. Predicate <T>
💙Что делает: Проверяет условие.
💙 Метод: boolean test(T t)
💙 Где нужен: Фильтрация стримов (`filter`), проверки.
2. Consumer <T>
💙 Что делает: "Потребляет" объект, ничего не возвращая.
💙 Метод: void accept(T t)
💙 Где нужен: Вывод на экран, запись в БД, forEach.
3. Supplier <T>
💙 Что делает: "Поставляет" объект (из ниоткуда), ничего не принимая.
💙 Метод: T get()
💙 Где нужен: Ленивая инициализация, генерация значений, orElseGet.
4. Function <T, R>
💙 Что делает: Превращает объект типа T в объект типа R.
💙 Метод: R apply(T t)
💙 Где нужен: Преобразование данных, map в стримах.
💻 Пример в коде
@FunctionalInterface
interface Converter {
int stringToInt(String s);
}
public class Main {
public static void main(String[] args) {
// 1. Создаем реализацию через лямбду
Converter converter = str -> Integer.parseInt(str);
// 2. Использование стандартного Consumer
java.util.function.Consumer<Integer> print = x -> System.out.println("Result: " + x);
int result = converter.stringToInt("123");
print.accept(result); // Вывод: Result: 123
}
}
java.util.function, чтобы ваш код был понятен другим разработчикам без лишних документаций.
🧵 String.join(): Склеиваем строки без боли
Помните те времена, когда для объединения списка строк через запятую приходилось писать циклы, использовать StringBuilder, а потом еще и аккуратно удалять последний разделитель? 🤯
Начиная с Java 8, у нас есть элегантный статический метод String.join, который делает код чистым и читаемым.
🛠 Как это работает?
Метод принимает разделитель (delimiter) и элементы, которые нужно склеить. Элементами могут быть как просто перечисление строк (varargs), так и любая коллекция (Iterable).
1️⃣ Пример с перечислением строк:
String result = String.join(" -> ", "Wake up", "Code", "Sleep");
System.out.println(result);
// Вывод: Wake up -> Code -> Sleep
List<String> langs = Arrays.asList("Java", "Kotlin", "Groovy");
// Больше никаких циклов!
String output = String.join(" | ", langs);
System.out.println(output);
// Вывод: Java | Kotlin | Groovy
null, вы получите NullPointerException. Но если null является одним из элементов списка, метод просто преобразует его в строку "null".StringJoiner (еще один класс из Java 8), что обеспечивает неплохую производительность по сравнению с обычной конкатенацией через +.String.join, когда у вас уже есть коллекция или массив строк, и вам нужно быстро собрать их в одну строку..collect(Collectors.joining(", "))
Совет Spring Framework💡
Вы можете инжектировать (autowire) бины, которые могут отсутствовать, обернув их в java.util.Optional. Таким образом вы сообщаете, что этот бин является необязательным, избегаете исключения, если он не существует, и можете аккуратно обработать его отсутствие с помощью Optional API.
📲 Мы в MAX
👉@BookJava
☕️ Spring Core: Зачем нужна аннотация @Bean?
Если вы работаете со Spring, вы видите эту аннотацию постоянно. Но чем она отличается от простого навешивания @Component над классом? Давайте разберем.
💡 Что это такое?
Аннотация @Bean используется в методах конфигурационных классов (помеченных @Configuration). Она говорит Spring-контейнеру:
"Эй, Spring! Выполни этот метод, возьми то, что он вернет, и сохрани этот объект у себя в контексте (ApplicationContext). Управляй им как бином".
@Configuration
public class AppConfig {
// Мы явно создаем объект и отдаем его Спрингу
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper(); // Например, библиотека Jackson
}
}
@Bean, а когда @Component?@Component (и @Service, @Repository), когда:component scanning). Вы просто ставите аннотацию над классом, и Spring сам его находит.@Bean, когда:ObjectMapper (из Jackson) или AmazonS3Client и написать там @Component, потому что это чужой код (read-only). Чтобы добавить такой объект в контекст Spring, вы создаете для него метод с @Bean.if/else) или сложной конфигурации, проще описать это в методе явно.@Bean@Bean("myCoolBean").@Bean(initMethod = "init", destroyMethod = "cleanup").@Bean нужны аргументы, Spring автоматически найдет и подставит их из контекста.@Component - для автоматизации своих классов, @Bean - для ручного контроля и чужих библиотек.
Совет SpringBoot
Вы можете запустить метод в Spring @Service сразу после запуска приложения, аннотируя его с помощью@EventListener (ApplicationReadyEvent.class). Метод не может иметь параметров. Иногда я неправильно использую его, чтобы быстро протестировать определенный метод Spring Service.
📲 Мы в MAX
👉@BookJava
⚡️ Микро-оптимизация: Прощай, AtomicInteger, привет, VarHandle!
👋 Сегодня поговорим о том, как можно немного ускорить ваш код, работающий с атомарными операциями, и сделать его более "современным" с помощью VarHandle, который появился в Java 9.
🧐 Проблема с AtomicIntegerAtomicInteger - это классический способ обеспечить атомарные операции (например, инкремент) над целым числом без блокировок, используя механизм Compare-And-Swap (CAS).
Однако, у него есть небольшой недостаток: он добавляет слой косвенности. Методы типа getAndIncrement() в AtomicInteger обычно вызывают внутренние статические методы из класса sun.misc.Unsafe (или его аналогов в более новых версиях), передавая в них ссылку на объект, смещение поля и новое значение.
// Примерно так это выглядит внутри AtomicInteger
// В реальном коде это, конечно, оптимизировано, но суть та же.
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
VarHandle!VarHandle - это новый, более гибкий и, что самое главное, более производительный низкоуровневый API для работы с полями переменных (как экземпляров, так и статических) с заданными барьерами памяти и атомарностью.VarHandle, чем через старые обертки типа AtomicInteger или прямые вызовы Unsafe.VarHandle вместо AtomicIntegerAtomicInteger, мы просто объявляем поле volatile в нашем классе и получаем VarHandle для этого поля.
public class Counter {
private volatile int count = 0; // Поле должно быть volatile
// ...
}
VarHandle:VarHandle нужно инициализировать один раз (обычно в статическом блоке) для доступа к полю.
private static final VarHandle COUNT_HANDLE;
static {
try {
// Получаем VarHandle для поля 'count' класса 'Counter' с типом int
COUNT_HANDLE = MethodHandles.lookup().findVarHandle(
Counter.class,
"count",
int.class
);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new Error(e);
}
}
getAndAdd VarHandle работает точно так же, как getAndAdd в AtomicInteger.
public int increment() {
// В отличие от AtomicInteger, где первый аргумент неявен,
// VarHandle требует первым аргументом *объект*,
// к полю которого мы обращаемся.
return (int) COUNT_HANDLE.getAndAdd(this, 1);
}
getAndAdd() через VarHandle могут быть незначительно быстрее (зачастую на 5-10%), чем те же операции через AtomicInteger, особенно под высокой нагрузкой, благодаря более эффективной генерации кода JIT-компилятором.🛑 Важно: Это микро-оптимизация. В большинстве приложений вы не заметите разницы. Но если вы пишете критически важные фреймворки, высоконагруженные коллекции или библиотеки, где каждая наносекунда на счету, переход на VarHandle может быть оправдан.VarHandle - это не только способ микро-оптимизации, но и стандартный, гибкий API для атомарного доступа, который заменил устаревший и менее безопасный Unsafe. Для нового кода, где требуется низкоуровневый атомарный доступ, стоит отдавать предпочтение именно ему.
Что такое «ссылка на метод»?
Если существующий в классе метод уже делает все, что необходимо, то можно воспользоваться механизмом method reference (ссылка на метод) для непосредственной передачи этого метода. Такая ссылка передается в виде:
⚫️имя_класса::имя_статического_метода для статического метода;
⚫️объект_класса::имя_метода для метода экземпляра;
⚫️название_класса::new для конструктора.
Результат будет в точности таким же, как в случае определения лямбда-выражения, которое вызывает этот метод.
private interface Measurable {
public int length(String string);
}
public static void main(String[] args) {
Measurable a = String::length;
System.out.println(a.length("abc"));
}
👩💻 Ваши Java-приложения под нагрузкой едва дышат? Профилирование и оптимизация кода остаются за скобками?
🎯 Курс «Java Developer. Advanced» от OTUS — это глубокое погружение в устройство JVM, байткод, сборщики мусора, профилирование и оптимизацию в облаке.
Наши эксперты-практики покажут, как выбрать GC, снять дамп памяти и обнаружить утечки, как профилировать “горячие” места, настраивать интеграцию с Prometheus & Grafana и деплоить сервисы в Kubernetes.
✔️ Вы научитесь обосновывать выбор JVM-имплементации, анализировать heap-дампы, синхронизировать потоки, использовать Reactor и неблокирующие I/O, проектировать метрики и трассировку.
➡️ Пройдите короткий тест и присоединяйтесь к группе: https://vk.cc/cRBJWK
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Микросервисы на основе событий с Kafka Streams и Spring Boot
Всем привет! Это моя первая статья на Habr, так что не судите строго за стиль, а вот по содержанию буду рад любой конструктивной критике.
Статья основана на публикациях Confluent о том, как можно реализовать микросервисную архитектуру на основе событий с помощью Kafka Streams и KSQL.
https://habr.com/ru/articles/775900/
📲 Мы в MAX
👉@BookJava
Совет 💡
Добавьте в JDBC URL свойство ApplicationName (зависит от БД, не в каждой БД оно есть!). Таким образом, в списке сессий вместо имени JDBC-драйвера будет отображаться имя набора. Это поможет при поиске неисправностей, когда несколько приложений подключаются к одной и той же БД.
📲 Мы в MAX
👉@BookJava
🏗 Курс “Software Architect” от OTUS — набор заканчивается! 🚨
Успейте занять место в группе курса «Software Architect»! Станьте экспертом в проектировании отказоустойчивых и масштабируемых систем. Пройдите вступительный тест и получите скидку, чтобы не пропустить старт обучения!
✅ Почему стоит пойти:
- 100% практики на реальных проектах
- Проектирование гибких архитектур
- Микросервисы, интеграции, Big Data
- Современные паттерны: CQRS, Event Sourcing
- Карьерный рост: рекомендации партнёрам для лучших
✅ Кому подойдёт:
- Разработчики, готовые к новому уровню
- Архитекторы, углубляющие экспертизу
- Тимлиды
✅ Что освоите:
- Проектирование масштабируемых архитектур
- Оптимизация взаимодействия сервисов
- Повышение качества и устойчивости систем
📌 Пройдите тест и забронируйте место со скидкой. Не упустите шанс стать экспертом в архитектуре систем! Подробности уточняйте у менеджера
👉 Пройти тестирование https://vk.cc/cRpnlp
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Совет по Spring Boot 💡
Вы думаете о замене 🍃RestTemplate на новый Spring RestClient? Конфигурация SSL очень проста благодаря поддержке 🔐SslBundles через интерфейс RestClientSsl
📲 Мы в MAX
👉@BookJava
Дорогие друзья, с Новым Годом!!!
Читать полностью…
Spring Boot Tutorial | Полный курс
В этом учебном пособии по Spring Boot рассказывается о том, как начать работу с Spring Boot и Java.
00:00 Intro
01:00 Quick Word
02:12 Spring Boot Overview
03:44 Project Overview
04:28 Spring Initializr
08:05 IntelliJ
10:29 Starting The Server
14:03 Simple API with Spring Boot
18:06 Student Class
23:19 API Layer
26:38 Business Layer
29:08 Dependency Injection
32:47 Properties file
36:15 Creating and Connecting to Database
39:48 JPA and @ Entity
42:35 JPA in Action
45:52 Amigoscode Database Courses
47:35 JPA Repository
52:20 Saving Students
58:49 @ Transient
01:03:01 Post Mapping
01:08:00 Writing Business Logic
01:12:43 Testing Post Request
01:15:35 Deleting Students
01:21:33 Exercise
01:22:53 Solution
01:26:54 Testing
01:29:41 Packaging and Running Application
01:34:52 Next steps
источник
📲 Мы в MAX
👉@BookJava
🚀 Функциональные интерфейсы: Level Up
В первой части мы разобрали «Великолепную четверку» (Predicate, Consumer, Supplier, Function). Но что делать, если нужно принять два аргумента? Или если тип входа и выхода совпадает, и лень писать лишний код?
Для этого в Java есть Bi-версии и Операторы.
👯 Семейство «Bi» (Два аргумента)
Стандартные интерфейсы принимают только один параметр. Если вам нужно обработать пару значений (например, ключ и значение из Map), используйте приставку Bi.
1. BiPredicate <T, U>
💙 Метод: boolean test(T t, U u)
💙 Пример: Проверить, что длина строки T больше числа U.
2. BiConsumer <T, U>
💙 Метод: void accept(T t, U u)
💙 Пример: map.forEach((k, v) -> ...) - классический пример использования.
3. BiFunction <T, U, R>
💙 Метод: R apply(T t, U u)
💙 Пример: Сложить число T и число U, получить результат R.
🔄 Семейство «Operator» (Один и тот же тип)
Часто бывает, что вы преобразуете объект, не меняя его тип (String -> String, int -> int). Писать Function<String, String> - слишком длинно.
1. UnaryOperator <T>
💙 Наследник Function<T, T>.
💙 Пример: str -> str.toUpperCase() (принимает строку, возвращает строку).
2. BinaryOperator <T>
💙 Наследник BiFunction<T, T, T>.
💙 Пример: (a, b) -> a + b (два числа на вход, одно число на выход). Именно он используется в Stream.reduce.
⚡ Осторожно с боксингом!
Дженерики (<T>) работают только с объектами. Если вы используете Function<Integer, Integer> для математики, Java будет постоянно распаковывать и запаковывать int в Integer, что бьет по производительности.
Для примитивов есть свои спецназовцы:
💙 IntPredicate, LongConsumer, DoubleFunction и т.д.
💙 Правило: Если работаете с числами - всегда ищите примитивный аналог интерфейса.
💻 Пример в коде
import java.util.function.*;
public class AdvancedLambdas {
public static void main(String[] args) {
// 1. BinaryOperator: объединяем две строки
BinaryOperator<String> concat = (s1, s2) -> s1 + " " + s2;
System.out.println(concat.apply("Hello", "Java"));
// 2. BiPredicate: проверяем, начинается ли строка с префикса
BiPredicate<String, String> startsWith = (str, prefix) -> str.startsWith(prefix);
System.out.println(startsWith.test("Telegram", "Tele")); // true
// 3. IntUnaryOperator: работаем с примитивами без лишних объектов
IntUnaryOperator square = x -> x * x;
System.out.println(square.applyAsInt(5)); // 25
}
}
int/long/double? Ищите интерфейсы с префиксом типа.
Использование метода String.join
Метод String.join можно использовать для объединения строк с заданным разделителем.
List<String> items = Arrays.asList("Apple", "Banana", "Cherry");
String result = String.join(", ", items);
System.out.println(result); // Output: Apple, Banana, Cherry
⌨️ Открытый урок «Тестирование Spring приложений. Интеграционные тесты с контекстом. Тестирование слоя репозиториев и сервисов».
🗓 25 декабря в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Разработчик на Spring Framework».
Интеграционные тесты в Spring: тестовый контекст, репозитории (JDBC/JPA), сервисы и транзакции.
На вебинаре:
✔️Особенности интеграционных тестов с поднятием контекста Spring.
✔️Тестирование слоя репозиториев: JDBC и JPA.
✔️Работа с транзакциями на сервисном слое и подходы к тестированию.
Кому будет полезно:
Backend-разработчикам на Java, начинающим осваивать тестирование Spring-приложений.
Что вы получите:
Разберётесь в базе интеграционного тестирования со Spring-контекстом и сможете написать простые тесты для репозиториев и сервисов.
🔗 Ссылка на регистрацию: https://vk.cc/cSrDoD
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🔍 Завтра тестовое собеседование с Java-разработчиком
17 декабря(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Сергею
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе.
Использование лямбда-выражений и Streams:
Лямбда-выражения и streams делают код более лаконичным и читаемым.
List<String> names = Arrays.asList("John", "Jane", "Jack", "Doe");
names.stream()
.filter(name -> name.startsWith("J"))
.map(String::toUpperCase)
.forEach(System.out::println);
Совет
По умолчанию при обновлении сущности Hibernate обновляет все ее поля. Вы можете использовать аннотацию @DynamicUpdate на объекте @Entity и Hibernate будет обновлять только те столбцы, которые изменились.
📲 Мы в MAX
👉@BookJava
Использование Optional для избежания NullPointerException:
Optional — это контейнер, который может содержать или не содержать ненулевое значение.
Optional<String> optional = Optional.ofNullable(getValue());
optional.ifPresentOrElse(
value -> System.out.println("Value is present: " + value),
() -> System.out.println("Value is absent")
);
Совет по Java 💡
Использование try-with-resources для автоматического управления ресурсами
Оператор try-with-resources гарантирует, что каждый ресурс будет закрыт в конце оператора.
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
Многопоточность
Как можно создать потоки в Java?
Как устроить Deadlock, а затем уйти от взаимной блокировки навсегда
Два самых полезных слова в многопоточности join() и Future
источник
📲 Мы в MAX
👉@BookJava
Неожиданное введение в Spring MVC
Spring MVC кажется сложным — пока не поймёшь, как он вырос из обычных сервлетов. На вебинаре шаг за шагом соберём свой первый фреймворк и разберёмся, зачем нужен MVC.
Приглашаем на открытый урок.
📅 Встречаемся 24 ноября в 20:00 мск.
Расскажет Александр Оруджев — Senior Software Engineer. Встречаемся на бесплатном практическом уроке от OTUS, где вы вместе с опытным экспертом разберете:
• как сервлеты превратились в контроллеры;
• что делает Spring под капотом;
• как построить собственный мини-MVC и понять принципы работы фреймворка.
После вебинара вы:
— поймёте архитектуру MVC без заучивания;
— перестанете бояться Spring MVC и начнёте использовать его осознанно;
— сделаете первый шаг к системному пониманию backend-разработки.
24 ноября в 20:00 открытый урок проходит в преддверие старта курса «Разработчик на Spring Framework». Все участники получат скидку на обучение.
👉 Регистрация бесплатная, но количество мест ограничено — успей занять своё место: https://vk.cc/cRv9kP
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Совет 🚀 Spring Retry 🚀
Spring Retry предлагает возможность автоматического повторного выполнения неудачной операции. 🔥
https://github.com/spring-projects/spring-retry
📲 Мы в MAX
👉@BookJava
Опишите поведение аннотации @Autowired
1. Контейнер определяет тип объекта для внедрения
2. Контейнер ищет бины в контексте(он же контейнер), которые соответствуют нужному типу
3. Если есть несколько кандидатов, и один из них помечен как @Primary, то внедряется он
4. Если используется аннотации @Autowire + Qualifier, то контейнер будет использовать информацию из @Qualifier, чтобы понять, какой компонент внедрять
5. В противном случае контейнер попытается внедрить компонент, основываясь на его имени или ID
6. Если ни один из способов не сработал, то будет выброшено исключение
Контейнер обрабатывает DI с помощью AutowiredAnnotationBeanPostProcessor. В связи с этим, аннотация не может быть использована ни в одном BeanFactoryPP или BeanPP.
Если внедряемый объект массив, коллекция, или map с дженериком, то Spring внедрит все бины подходящие по типу в этот массив(или другую структуру данных). В случае с map ключом будет имя бина.
//параметр указывает, требуется ли DI@Authowired(required = true/false)
📲 Мы в MAX
👉@BookJava
🎥 Открытый урок «Java Memory Model: как синхронизировать потоки».
🗓 20 ноября в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Advanced».
JMM определяет, как JVM видит память: что наблюдают потоки и где нужна синхронизация — база корректного многопоточного кода.