Недавно в очередной раз столкнулся с холиваром: "Зачем ты переписал properties в yaml?" Давайте разбираться.
🔹 Properties — старая гвардия
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=admin
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
🔹 YAML — современный подход
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: admin
password: secret
jpa:
hibernate:
ddl-auto: validate
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
🔹 Технические нюансы
— Парсинг и производительность: properties парсится через java.util.Properties (простой key-value), YAML требует SnakeYAML библиотеку. На старте приложения разница незаметна, но YAML чуть медленнее из-за построения объектной модели.
— Приоритет загрузки: Spring Boot загружает конфиги в порядке: application.properties → application.yml → application-{profile}.properties → application-{profile}.yml. Если есть оба формата, properties имеет приоритет над yaml для одинаковых ключей.
— Списки и массивы: в YAML естественная запись списков, в properties приходится использовать индексы.
— Placeholder resolution: оба формата поддерживают ${variable:default}, но в YAML нужно быть осторожным с экранированием двоеточий в URL.
— Невалидный синтаксис: properties молча проигнорирует строку без =, YAML упадёт с исключением при старте приложения — это и минус, и плюс одновременно.
— @PropertySource ограничение: аннотация работает только с .properties, для YAML нужно писать кастомный PropertySourceFactory.
YAML для основной конфигурации приложения — структура и удобство работы со сложными объектами того стоят. Properties для специфичных кейсов: custom property sources с @PropertySource, legacy интеграции, простые CI/CD переменные, конфиги для библиотек без Spring контекста.
В production проектах часто вижу гибридный подход: application.yml для базовой структуры + application-{env}.properties для переопределения специфичных параметров окружения через environment variables.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤4🔥1
Please open Telegram to view this post
VIEW IN TELEGRAM
❤🔥18😁14💯9👍3🙏1
Если ты хоть раз создавал Map<String, List<String>>, то пост для тебя.
Признай, каждый когда-нибудь писал:
Map<String, List<String>> userTags = new HashMap<>();
userTags.computeIfAbsent("user123", k -> new ArrayList<>()).add("premium");
userTags.computeIfAbsent("user123", k -> new ArrayList<>()).add("verified");
Или ещё хуже:
if (!userTags.containsKey("user123")) {
userTags.put("user123", new ArrayList<>());
}
userTags.get("user123").add("premium");Apache Commons Collections давно придумал MultiValuedMap.
🔹 Что это такое
MultiValuedMap<K, V> — это структура данных, которая позволяет хранить несколько значений для одного ключа. По сути, это Map<K, Collection<V>>, но с нормальным API.
MultiValuedMap<String, String> userTags = new ArrayListValuedHashMap<>();
userTags.put("user123", "premium");
userTags.put("user123", "verified");
userTags.put("user123", "early-adopter");
// Получаем все теги разом
Collection<String> tags = userTags.get("user123");
// [premium, verified, early-adopter]
Никаких computeIfAbsent, никаких проверок на null. Просто работает.
🔹 Что умеет
— Добавление без боли:
multiMap.put("key", "value1");
multiMap.put("key", "value2"); // не перезатирает предыдущее значение— Массовые операции:
multiMap.putAll("user456", Arrays.asList("admin", "moderator"));— Проверка наличия:
multiMap.containsMapping("user123", "premium"); // true/false— Удаление конкретного значения:
multiMap.removeMapping("user123", "premium");— Получение всех значений:
Collection<String> allTags = multiMap.values();
// все значения из всех ключей
🔹 Реализации
→ ArrayListValuedHashMap<K, V> — значения хранятся в ArrayList, порядок сохраняется, дубликаты разрешены
→ HashSetValuedHashMap<K, V> — значения хранятся в HashSet, без дубликатов
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥23👍11👏2❤1
В связи с последними новостями созрел вопрос. Где бы кроме тг вы могли читать наш канал?
Пишите в комменты/лайкайте чужие ответы, какие ещё платформы с подобным контентом вы используете сейчас или были бы готовы использовать в будущем вместо тг?
#DevLife
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1🔥1👏1
Java developer — 250 000 ₽ — удалёнка
Java Backend Developer — от 250 000 ₽ — офис/гибрид (Москва, Санкт-Петербург)
Руководитель разработки (Java) — 350 000 — 425 000 ₽ — гибрид (Москва)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1👏1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁37💯5🔥2❤1
Раньше switch был ограничен примитивами и enum'ами. С Java 21 Pattern Matching стал стандартом, и это принципиально меняет подход к обработке полиморфных данных.
Object obj = getObject();
String result;
if (obj instanceof String s) {
result = "String: " + s;
} else if (obj instanceof Integer i) {
result = "Int: " + i;
} else {
result = "Unknown";
}
String result = switch (obj) {
case String s -> "String: " + s;
case Integer i -> "Int: " + i;
case null -> "Null!";
default -> "Unknown";
};Но суть не в синтаксисе. Суть в гарантиях компилятора.
🔹 Охранные выражения (guarded patterns)
String classify(Object obj) {
return switch (obj) {
case String s when s.length() > 10 -> "Long string";
case String s -> "Short string";
case Integer i when i > 0 -> "Positive";
case Integer i -> "Non-positive";
case null -> "Null";
default -> "Other";
};
}Условия when проверяются последовательно. Компилятор отслеживает полноту покрытия и недостижимый код. Поменяете порядок кейсов неправильно — получите ошибку компиляции.
🔹 Record patterns — деструктуризация на месте
record Point(int x, int y) {}
String describe(Object obj) {
return switch (obj) {
case Point(int x, int y) when x == y ->
"Diagonal point";
case Point(int x, int y) ->
"Point at (%d, %d)".formatted(x, y);
default -> "Not a point";
};
}Распаковали record прямо в case. Никаких геттеров, никаких промежуточных переменных.
🔹 Sealed классы + pattern matching = полнота проверок
sealed interface Result permits Success, Failure {}
record Success(String data) implements Result {}
record Failure(String error) implements Result {}
String handle(Result result) {
return switch (result) {
case Success(String data) -> "Got: " + data;
case Failure(String error) -> "Error: " + error;
// default не нужен - компилятор знает все варианты
};
}Компилятор гарантирует, что вы обработали все случаи. Добавите новый класс в sealed иерархию — код не скомпилится, пока не обработаете его.
JIT оптимизирует pattern matching свитчи агрессивно. В бенчмарках разница с if-else цепочками от 2x до 10x в пользу switch в зависимости от количества веток.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍7❤1⚡1👏1
Каждый раз, когда вы набираете https://example.com в браузере, за кулисами запускается целая цепочка событий.
Браузер делит URL на части:
▪️ https — протокол
▪️ example.com — домен
▪️ /page — путь к ресурсу
Если IP не сохранён в кеше, браузер спрашивает DNS-сервер: «Где живёт example.com?»
Создаётся TCP-соединение с сервером по IP и порту (80 для HTTP, 443 для HTTPS).
Браузер отправляет HTTP-запрос: GET /page HTTP/1.1
Сервер возвращает HTML, CSS, JS и статус-код (например, 200 OK или 404 Not Found).
Браузер обрабатывает HTML, применяет стили и выполняет JavaScript.
Если сайт работает по HTTPS, соединение шифруется через SSL/TLS.
Браузер сохраняет ресурсы, чтобы при следующем визите всё грузилось быстрее.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2🔥1👏1
🔹 RestTemplate
javaRestTemplate restTemplate = new RestTemplate();
ResponseEntity<User> response = restTemplate.getForEntity(
"https://api.example.com/users/{id}",
User.class,
userId
);
User user = response.getBody();
🔹 WebClient
javaWebClient webClient = WebClient.create("https://api.example.com");
Mono<User> userMono = webClient.get()
.uri("/users/{id}", userId)
.retrieve()
.bodyToMono(User.class);🔹 Технические нюансы
— Thread model: RestTemplate использует по потоку на запрос (blocking I/O). WebClient работает на event loop с малым числом потоков (по умолчанию CPU cores * 2).
— Performance: в синхронных сценариях разница минимальна. При параллельных запросах WebClient показывает x2-x5 прирост throughput за счёт эффективного использования потоков.
— Memory footprint: 1000 параллельных REST вызовов через RestTemplate = ~1000 МБ стека потоков. WebClient с той же нагрузкой — десятки МБ.
— Timeout configuration: RestTemplate требует настройки через ClientHttpRequestFactory. WebClient имеет встроенный .timeout(Duration) в цепочке вызовов.
— Error handling: RestTemplate выбрасывает исключения синхронно. WebClient возвращает Mono с ошибкой.
— Testing: RestTemplate легко мокается через MockRestServiceServer. WebClient требует понимания StepVerifier из reactor-test.
— Compatibility: RestTemplate работает везде. WebClient требует Spring WebFlux в classpath, даже если используешь его в обычном Spring MVC приложении.
WebClient если стартуешь новый проект, делаешь микросервисы с высокой нагрузкой, уже используешь reactive stack или планируешь масштабироваться. RestTemplate если поддерживаешь legacy код без реактивности, команда не знакома с Project Reactor, делаешь простой CRUD сервис с малой нагрузкой.
Главное помни: преждевременная оптимизация — корень зла. Если RestTemplate закрывает задачу, не усложняй. Но если упираешься в потоки на проде, время учить реактивщину.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3❤2👏1
Собираем фулл-хаус: 3 курса по цене 1
Хватит выбирать между «полезно», «модно» и «для души». Мы запустили механику, которая позволяет собрать кастомный стек навыков без удара по бюджету: покупаете один курс — два других забираете бесплатно.
Java-разработка немыслима без паттернов. Забирайте архитектуру и шаблоны проектирования, чтобы говорить на одном языке с сеньорами. Для прохождения фильтров в корпорации — алгоритмы и структуры данных.
Для тех, кто смотрит в сторону Data Engineering или ML — полный набор по AI: от математики и ML-старта до разработки автономных агентов.
Ну и классика: обновлённый Python как удобный инструмент для вспомогательных скриптов.
Собрать свой пак
Хватит выбирать между «полезно», «модно» и «для души». Мы запустили механику, которая позволяет собрать кастомный стек навыков без удара по бюджету: покупаете один курс — два других забираете бесплатно.
Java-разработка немыслима без паттернов. Забирайте архитектуру и шаблоны проектирования, чтобы говорить на одном языке с сеньорами. Для прохождения фильтров в корпорации — алгоритмы и структуры данных.
Для тех, кто смотрит в сторону Data Engineering или ML — полный набор по AI: от математики и ML-старта до разработки автономных агентов.
Ну и классика: обновлённый Python как удобный инструмент для вспомогательных скриптов.
Собрать свой пак
Начиная с Spring 4.2 (2015 год!), классы событий больше не обязаны наследовать ApplicationEvent.
🔹 До Spring 4.2:
public class UserCreatedEvent extends ApplicationEvent {
private final String username;
public UserCreatedEvent(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
}🔹 Начиная с Spring 4.2+:
// Просто POJO
public class UserCreatedEvent {
private final String username;
public UserCreatedEvent(String username) {
this.username = username;
}
// getters...
}
🔹 Использование идентично:
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher publisher;
public void createUser(String username) {
publisher.publishEvent(new UserCreatedEvent(username));
}
}
@EventListener
public void onUserCreated(UserCreatedEvent event) {
log.info("User created: {}", event.username());
}
Использование обычных POJO-классов в качестве событий делает код независимым от Spring Framework, что улучшает тестируемость и переносимость приложения.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍4❤2🤔2
Please open Telegram to view this post
VIEW IN TELEGRAM
😁24💯4🔥3
Forwarded from Библиотека собеса по Java | вопросы с собеседований
Напишите production-ready Spring компонент 👇
📦 Задание
Реализуйте кастомную аннотацию @RateLimit, которая ограничивает количество вызовов метода с использованием Spring AOP.
🔹 Требования
— Использовать Spring AOP
— Потокобезопасность
— Кэш лимитов
— Учитывать имя метода + параметры
— Custom exception при превышении
Ставьте → 🔥, если нравится формат. Если нет → 🤔
#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥22❤2👍2👏1🤔1
Нужно изменить одинаковый код в 10 местах? Обычно делаешь Find & Replace или правишь вручную каждую строку. Есть способ быстрее — Multiple Cursors. Редактируешь несколько мест одновременно.
🔹 Что это
Несколько курсоров в редакторе. Печатаешь один раз — изменения применяются везде сразу. Как Vim visual block mode, но удобнее.
🔹 Как использовать
— Alt+J (Win/Linux) или Ctrl+G (Mac) — выделить следующее вхождение слова под курсором
— Alt+Shift+J — убрать последний курсор
— Ctrl+Alt+Shift+J — выделить ВСЕ вхождения сразу
— Alt+Shift+Click — поставить курсор мышью
— Alt+Shift+Insert → Column Selection Mode — выделение столбцом
🔹 Зачем это нужно
— Массовое редактирование без регулярок
— Быстрее Find & Replace для простых случаев
— Видишь изменения сразу, контролируешь процесс
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥5❤1👏1😁1
This media is not supported in your browser
VIEW IN TELEGRAM
Платформа с реальными DevOps-задачами. Кейсы по Linux, Docker и Kubernetes — всё как в бою, но с читами:
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥4👏1
🔬 Правильный вопрос про AI
Все исследования AI-ассистентов меряют одно: насколько быстрее ты закрываешь задачу. Метрика удобная, но она игнорирует 70–80% реальных затрат — поддержку, рефакторинг, устранение дефектов.
Исследование «Echoes of AI» (arXiv, 2025) спросило другое:
«Что будет, когда другой разработчик возьмёт AI-код и попытается его развивать?»
151 участник, 95% практикующие разработчики (не студенты). Java/Spring Boot проект, две фазы, настоящее РКИ. Одна группа пишет с AI, другая без. Потом третья группа без AI поддерживает и тот, и другой код.
Результат оказался неожиданный.
👉 Читать
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
Все исследования AI-ассистентов меряют одно: насколько быстрее ты закрываешь задачу. Метрика удобная, но она игнорирует 70–80% реальных затрат — поддержку, рефакторинг, устранение дефектов.
Исследование «Echoes of AI» (arXiv, 2025) спросило другое:
«Что будет, когда другой разработчик возьмёт AI-код и попытается его развивать?»
151 участник, 95% практикующие разработчики (не студенты). Java/Spring Boot проект, две фазы, настоящее РКИ. Одна группа пишет с AI, другая без. Потом третья группа без AI поддерживает и тот, и другой код.
Результат оказался неожиданный.
👉 Читать
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1🔥1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁25👍3❤2💯1
Forwarded from Библиотека задач по Java | тесты, код, задания
В каком порядке выполнятся операции при создании Spring-бина?
Anonymous Quiz
32%
Constructor → @Autowired → @PostConstruct → InitializingBean.afterPropertiesSet()
22%
@Autowired → Constructor → @PostConstruct → InitializingBean.afterPropertiesSet()
28%
Constructor → @PostConstruct → @Autowired → InitializingBean.afterPropertiesSet()
8%
@PostConstruct → Constructor → @Autowired → InitializingBean.afterPropertiesSet()
9%
Посмотреть ответ
👍4🔥3❤2👏1
🧩 Просто о сложном: Saga Pattern
Когда пользователь оформляет заказ, нужно списать деньги, зарезервировать товар и уведомить склад. Всё в разных сервисах. Что делать, если один из них упал?
Обычная транзакция тут не поможет. Добро пожаловать в Saga.
Идея проста: разбиваем большую распределённую транзакцию на цепочку маленьких локальных. Каждый шаг — это своя транзакция в своём сервисе. Если что-то пошло не так, то запускаем компенсирующие транзакции в обратном порядке.
🔹 Два подхода
1. Choreography (хореография)
Сервисы общаются через события. Каждый сам знает, что делать дальше.
✔️ Просто, нет единой точки отказа
❌ Сложно отследить весь флоу, спагетти из событий
2. Orchestration (оркестрация)
Есть дирижёр — Saga Orchestrator. Он знает весь сценарий и командует сервисами.
✔️ Флоу виден в одном месте, легко дебажить
❌ Оркестратор может стать узким местом
⚠️ Важно понимать: компенсирующая транзакция ≠ откат БД. Это бизнес-операция. Если деньги уже списаны, то мы не откатываем строку в БД, мы делаем возврат.
В Java-экосистеме Saga используют вместе с:
→ Apache Kafka / RabbitMQ — для событий между сервисами
→ Axon Framework — встроенная поддержка Saga из коробки
→ Spring State Machine — для управления состоянием оркестратора
→ Temporal / Conductor — оркестрация workflow на уровне инфраструктуры
🔹 Когда использовать
✔️ Микросервисная архитектура
✔️ Несколько БД, нет возможности использовать 2PC
✔️ Долгоживущие бизнес-транзакции
❌ Монолит с одной БД — просто используй @Transactional
Saga — это не серебряная пуля, это компромисс. Ты жертвуешь изоляцией ради масштабируемости. Данные могут быть временно не консистентны и это нормально, если бизнес с этим согласен.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
Когда пользователь оформляет заказ, нужно списать деньги, зарезервировать товар и уведомить склад. Всё в разных сервисах. Что делать, если один из них упал?
Обычная транзакция тут не поможет. Добро пожаловать в Saga.
Идея проста: разбиваем большую распределённую транзакцию на цепочку маленьких локальных. Каждый шаг — это своя транзакция в своём сервисе. Если что-то пошло не так, то запускаем компенсирующие транзакции в обратном порядке.
🔹 Два подхода
1. Choreography (хореография)
Сервисы общаются через события. Каждый сам знает, что делать дальше.
OrderService → [OrderCreated] → PaymentService
PaymentService → [PaymentDone] → InventoryService
InventoryService → [Reserved] → NotificationService
2. Orchestration (оркестрация)
Есть дирижёр — Saga Orchestrator. Он знает весь сценарий и командует сервисами.
public class OrderSagaOrchestrator {
public void execute(Order order) {
try {
paymentService.charge(order);
inventoryService.reserve(order);
notificationService.notify(order);
} catch (PaymentException e) {
// компенсация не нужна — деньги не списаны
} catch (InventoryException e) {
paymentService.refund(order); // компенсируем
}
}
}В Java-экосистеме Saga используют вместе с:
→ Apache Kafka / RabbitMQ — для событий между сервисами
→ Axon Framework — встроенная поддержка Saga из коробки
→ Spring State Machine — для управления состоянием оркестратора
→ Temporal / Conductor — оркестрация workflow на уровне инфраструктуры
🔹 Когда использовать
Saga — это не серебряная пуля, это компромисс. Ты жертвуешь изоляцией ради масштабируемости. Данные могут быть временно не консистентны и это нормально, если бизнес с этим согласен.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2🔥2👏1👾1
Enterprise AI: когда MVP уже не прокатит
В корпоративном секторе требования к AI жёстче: безопасность, стабильность, работа с документами. Мы обновили курс «Разработка AI-агентов», добавив модули, критически важные для Enterprise-разработки.
Java-инженерам будет интересно:
🔹 Advanced RAG. Работа со сложной корпоративной документацией (сканы, таблицы), улучшение поиска и безопасности данных.
🔹 Legal Tech. Как внедрять агентов с соблюдением 152-ФЗ и юридических норм.
🔹 Надёжность. Внедрение
🔹 Legacy. Управление браузером и старыми интерфейсами через агентов.
Стартуй сейчас! Покупаешь курс — сразу получаешь материалы.
🎟 ПромокодAgent — скидка 10 000 ₽ (до 28 февраля).
👉 AI для Enterprise-задач
В корпоративном секторе требования к AI жёстче: безопасность, стабильность, работа с документами. Мы обновили курс «Разработка AI-агентов», добавив модули, критически важные для Enterprise-разработки.
Java-инженерам будет интересно:
🔹 Advanced RAG. Работа со сложной корпоративной документацией (сканы, таблицы), улучшение поиска и безопасности данных.
🔹 Legal Tech. Как внедрять агентов с соблюдением 152-ФЗ и юридических норм.
🔹 Надёжность. Внедрение
Human-in-the-loop для контроля, логирование, трассировка и предотвращение регрессий.🔹 Legacy. Управление браузером и старыми интерфейсами через агентов.
Стартуй сейчас! Покупаешь курс — сразу получаешь материалы.
🎟 Промокод
👉 AI для Enterprise-задач
Java-разработчик — Офис (Казань)
Java-разработчик — от 230 000 до 330 000 ₽ — удалёнка/гибрид (Москва)
Senior Java Developer (Kotlin) — от 400 000 ₽ — удалёнка
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1🔥1