uz
Feedback

Firibgarlarga uchmang! Telemetrio bunday kanallarni topadi va belgilaydi 👉 Belgini ko‘rmoqchi bo‘lsangiz, obuna bo‘ling

Java Geek

Java Geek

Kanalga Telegram’da o‘tish

Практичные советы, лайфхаки и код для Java-разработчиков. Каждый пост — реальная польза. Учим Java на примерах. По всем вопросам @evgenycarter

Ko'proq ko'rsatish
2 354
Obunachilar
-124 soatlar
-37 kun
-1530 kun
Postlar arxiv
Как прогреть кэши в Spring Boot, чтобы убрать «холодный старт» 🧠 Идея простая: не лезьте напрямую в CacheManager. Прогревайте через те же @Cacheable методы, которые используются в рантайме - так вы не обходите unless, ключи и TTL провайдера. 📌 Минимальная реализация (Boot 3+, Java 17/21)

// Сервис с кэшем
@Service
public class CatalogService {
  @Cacheable(cacheNames = "products", key = "#id", unless = "#result == null")
  public Product getById(Long id) {
    // дорогой вызов в БД/REST
  }
}

// Прогрев после полной готовности приложения
@Component
@RequiredArgsConstructor
public class CacheWarmup {

  private final CatalogService catalog;

  @EventListener(org.springframework.boot.context.event.ApplicationReadyEvent.class)
  public void warm() {
    if (!isEnabled()) return;

    var hotIds = loadHotProductIds();      // топ-ключи из БД/конфига
    try (var exec = java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()) {
      // ограничьте параллелизм при необходимости (Semaphore)
      hotIds.stream()
            .map(id -> java.util.concurrent.CompletableFuture.supplyAsync(() -> catalog.getById(id), exec))
            .forEach(java.util.concurrent.CompletableFuture::join);
    }
  }

  private boolean isEnabled() { return true; } // читайте из настроек/профиля
  private List<Long> loadHotProductIds() { return List.of(1L,2L,3L,4L,5L); }
}
application.yml:

spring:
  cache:
    type: caffeine
    cache-names: products
    caffeine:
      spec: maximumSize=10000,expireAfterWrite=1h,recordStats
# Быстрый прогрев без блокировки потоков ОС (Java 21+)
spring.threads.virtual.enabled: true
💡 Где брать «горячие» ключи: топ-N по обращениями за последние 24–72 часа (лог/метрики); статические справочники (страны, тарифы); ключи, которые дергают критичные эндпоинты / главная страница. ⚠️ Важные нюансы: Не блокируйте старт сервиса надолго. Делайте прогрев асинхронно и с лимитом параллельных задач (Semaphore/FixedThreadPool). Падения прогрева ≠ падения приложения. Оберните в try/catch, логируйте, но не валите контекст. Health/Readiness. Если нужен «строгий» запуск, проверяйте готовность только по минимальному набору ключей, а остальное догревайте фоном. Кластеры. В Redis/общем кеше греть можно с одного инстанса (feature-flag), чтобы не дублировать трафик. В локальных (Caffeine) - грейте на каждом. Обновление после прогрева. Для данных, которые быстро стареют, добавьте @Scheduled обновление (@CacheEvict/@CachePut) или фоновые рефреши. 👉 @java_geek

⌨️ Как вырасти до Мидла или Синьора в два раза быстрее? 👨‍💻Просто хорошо работать работу не достаточно. Ты делаешь то, что
⌨️ Как вырасти до Мидла или Синьора в два раза быстрее? 👨‍💻Просто хорошо работать работу не достаточно. Ты делаешь то, что нужно компании, а не то, что повысит твой грейд Лучший способ вырасти — это персональный план развития от Senior-инженера из БигТеха. Вот как все работает: 1️⃣ Мок-интервью 1-на-1: Час реалистичного собеса с Senior-инженером из Иннотеха, Сбера или другого бигтеха 2️⃣ Честный фидбек: созвонимся и расскажем твои точки роста, оценим грейд и потенциальный уровень зарплаты 3️⃣Персональный план развития: не просто «учите алгосы», а роадмап с конкретными темами, который приведет тебя к желаемому грейду или офферу Мы в ШОРТКАТ провели уже почти 1000 таких мок-интервью и получили оценку 4.9/5, поэтому знаем о чем говорим. 📈 Да, и все это за 900 рублей. Почему так дешево? Мы хотим, чтобы у каждого была возможность проверить в деле наш сервис, а потом уже доверить нам свое развитие. Переходи в нашего бота и забирай свой мок за 900 рублей → @shortcut_sh_bot Реклама. О рекламодателе.

Class.getRecordComponents() Class.getRecordComponents() возвращает информацию о компонентах записи (record). Это полезно для
Class.getRecordComponents() Class.getRecordComponents() возвращает информацию о компонентах записи (record). Это полезно для рефлексии, сериализации и автоматического отображения данных в Record-классах. 👉 @java_geek

Какова цель ключевого слова final, когда оно используется с переменной? Ключевое слово final в Java — это модификатор, который может применяться к переменным, методам и классам. Когда оно используется с переменной, это делает её неизменяемой, другими словами — константой. Например, переменная PI объявлена как final в классе ниже:

public class CircleCalculator {
   private final double PI = 3.14159;
   public double calculateArea(double radius) {
       return PI * radius * radius;
   }
}
👉 @java_geek

☕ Java Tip: Как работает var в Java С версии Java 10 появился ключевое слово var. Оно упрощает код, автоматически выводя тип переменной:

var list = new ArrayList<String>();
list.add("Hello");
list.add("Java");

// Компилятор понимает, что list -> ArrayList<String>
✅ Удобно: меньше шаблонного кода. ❌ Важно: var не значит "динамическая типизация"! Тип фиксируется при компиляции. 📌 Используй var, если тип переменной очевиден - код станет чище. 👉 @java_geek

🔍 Завтра тестовое собеседование с Java-разработчиком 20 июля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседо
🔍 Завтра тестовое собеседование с Java-разработчиком 20 июля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Сергею Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. О рекламодателе.

Collections.nCopies() Collections.nCopies() создаёт неизменяемый список, содержащий заданное количество копий одного и того ж
Collections.nCopies() Collections.nCopies() создаёт неизменяемый список, содержащий заданное количество копий одного и того же объекта. Это полезно для инициализации, заглушек и создания шаблонных коллекций. 👉 @java_geek

Что такое перегрузка методов в Java? Перегрузка методов — это мощный приём, который позволяет классу иметь несколько методов с одинаковым именем, но разными параметрами. Это даёт объектам класса возможность обрабатывать близкие (почти одинаковые) задачи, но с разными входными данными. Вот очень короткий пример, демонстрирующий перегрузку методов:

class Calculator {
   int add(int a, int b) {
       return a + b;
   }
   double add(double a, double b) {
       return a + b;
   }
}
В этом примере класс Calculator имеет два метода add: один принимает два целых числа (int) и возвращает сумму в виде целого числа, а другой — два числа с плавающей запятой (double) и возвращает сумму в виде double. Имя метода одинаковое, но параметры различаются, что позволяет вызывать подходящий метод в зависимости от типов аргументов. 👉 @java_geek

Разница между операторами break и continue. break и continue — это важные ключевые слова для управления потоком выполнения циклов в Java. Оператор break используется для немедленного завершения всего цикла, игнорируя оставшийся код в нём. Он полезен, когда нужно досрочно прервать цикл при выполнении определённого условия. Например, я использую break для отладки, чтобы выполнить только одну итерацию длинного цикла. Оператор continue используется для пропуска оставшейся части текущей итерации и немедленного перехода к следующей. Он удобен, когда нужно проходить по последовательности и пропускать отдельные элементы при выполнении определённого условия. Пример кода:

for (int i = 0; i < 5; i++) {
   if (i == 2) {
       continue;  // Skip iteration when i is 2
   }
   if (i == 4) {
       break;     // Exit loop when i is 4
   }
   System.out.println(i);
}
👉 @java_geek

Объясните концепцию наследования в Java на примерах Наследование — один из ключевых принципов объектно-ориентированного программирования в Java. Оно позволяет одному классу наследовать свойства и методы другого класса, что способствует повторному использованию кода и устанавливает отношение «родитель–потомок» между классами. Например, класс Car может наследоваться от общего класса Vehicle. В этом случае Car может вести себя так же, как Vehicle, с точки зрения атрибутов и методов: - Класс Vehicle имеет такие члены, как year и make, а Car добавляет дополнительный член transmission. - Класс Vehicle имеет метод move, а Car переопределяет move, добавляя поведение, характерное для автомобилей. 👉 @java_geek

🔍Тестовое собеседование с Java-разработчиком из Oracle завтра 23 июля(уже завтра!) в 19:00 по мск приходи онлайн на открытое
🔍Тестовое собеседование с Java-разработчиком из Oracle завтра 23 июля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Алексей Ушаровский, разработчик с опытом работы в Oracle и EPAM, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Алексей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Алексею Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. О рекламодателе.

🧠 Ленивая инициализация @Component в Spring Boot По умолчанию Spring инициализирует все бины при старте приложения. Это удобно, но может замедлить запуск, особенно если есть тяжёлые компоненты — например, коннекторы к внешним сервисам, парсеры, или тяжёлые кэши. 📌 Решение — использовать ленивую инициализацию (@Lazy):

@Component
@Lazy
public class HeavyComponent {
    public HeavyComponent() {
        System.out.println("HeavyComponent инициализирован");
    }
}
Теперь бин будет создан только при первом обращении. Можно также внедрять лениво:

@Component
public class SomeService {
    private final HeavyComponent heavy;

    public SomeService(@Lazy HeavyComponent heavy) {
        this.heavy = heavy;
    }
}
💡 Если у вас много таких компонентов — можно включить ленивую инициализацию глобально:

spring:
  main:
    lazy-initialization: true
⚠️ Осторожно: это может скрыть ошибки конфигурации до первого использования бина, что усложняет отладку. Используйте осознанно. Идеально подходит для: — микросервисов с быстрым стартом — CLI-инструментов на Spring Boot — задач с heavy startup logic 👉 @java_geek

🧠 Неожиданный анти-паттерн в Spring Boot: @EventListener как тихий убийца производительности В Spring удобно использовать @EventListener для реактивных действий — казалось бы, удобно и "чисто". Но есть нюанс. 📌 По умолчанию все @EventListener вызываются синхронно и в том же потоке, где был опубликован ивент через ApplicationEventPublisher. Это значит:

@Component
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;

    public void createOrder(Order order) {
        // 1. Сохраняем заказ
        orderRepository.save(order);

        // 2. Публикуем ивент
        publisher.publishEvent(new OrderCreatedEvent(order));
        // 3. До выхода из метода все @EventListener уже будут выполнены
    }
}
А теперь представим, что слушатель делает что-то тяжёлое:

@EventListener
public void sendEmail(OrderCreatedEvent event) {
    emailService.sendConfirmation(event.getOrder());
}
⚠️ Если sendConfirmation висит на внешнем SMTP или уходит в сеть — метод createOrder будет ждать его завершения! 💡 Решение: сделать обработку асинхронной. Просто добавьте @Async:

@Async
@EventListener
public void sendEmail(OrderCreatedEvent event) {
    emailService.sendConfirmation(event.getOrder());
}
✅ И не забудьте включить поддержку @Async:

@EnableAsync
@Configuration
public class AsyncConfig {}
📌 Теперь @EventListener будет исполняться в отдельном потоке из TaskExecutor, и createOrder не будет блокироваться. 👉 @java_geek

VK приглашает на Java AI meetup 9 июля. Обещают доклады топовых спикеров из AI-департамента, тематическую дискуссию и много п
VK приглашает на Java AI meetup 9 июля. Обещают доклады топовых спикеров из AI-департамента, тематическую дискуссию и много полезных знакомств в индустрии. Подробнее — здесь.

🔥 Spring Native Image vs. Обычное Spring-приложение: В чем разница и зачем это нужно? Разбираемся, как нативные образы меняют правила игры для Spring-приложений! 👇 Обычное Spring-приложение (JVM-based): Когда вы запускаете классический Spring Boot на Java Virtual Machine (JVM), происходит следующее: 🔵JVM запускается первой: Прежде чем ваш код заработает, JVM должна инициализироваться и загрузить классы. Это занимает время. 🔵Динамическая природа: JVM позволяет динамически загружать классы и использовать рефлексию в рантайме. Это гибко, но ресурсозатратно. 🔵"Прогрев" (Warm-up): Для пиковой производительности JVM нужно время на JIT-компиляцию кода. 🔵Большой объем памяти: JVM сама по себе требует значительного объема RAM. 🔵Размер артефакта: JAR-файл содержит байт-код, который JVM затем обрабатывает. Spring Native Image (с GraalVM Native Image): Это компиляция вашего Spring-приложения в самостоятельный нативный исполняемый файл, не требующий JVM! 🔵Компиляция AOT (Ahead-of-Time): Весь код (включая Spring и JDK) компилируется в машинный код на этапе сборки. Все оптимизации происходят заранее. 🔵Мгновенный старт: Нет JVM и "прогрева"! Нативные образы стартуют мгновенно (от долей секунды). Идеально для: 🔵Серверлес-функций (Lambda, FaaS): Быстрый старт снижает задержки и стоимость. 🔵Микросервисов: Для быстрого масштабирования. 🔵Batch-задач: Быстрый запуск и завершение. 🔵Низкое потребление памяти: Отсутствие JVM значительно сокращает RAM. Экономия облачных ресурсов и возможность запускать больше приложений на сервере. 🔵Меньший размер образа: Включается только используемый код без JVM, что упрощает развертывание в контейнерах. 🔵Статический анализ: GraalVM глубоко анализирует код, исключая неиспользуемые части. Недостатки (куда без них?): 🔵Длительное время сборки: AOT-компиляция занимает значительно больше времени. 🔵Сложности с динамикой: Рефлексия и прокси требуют дополнительных настроек (runtime hints), хотя Spring Boot 3 упрощает это. 🔵Отсутствие некоторых инструментов мониторинга: Привычные JVM-инструменты (JMX, JFR) не поддерживаются напрямую. 🔵Специфичность платформы: Нужен отдельный образ для каждой ОС и архитектуры. Когда стоит использовать Spring Native Image? 🔵Когда время старта и потребление памяти критичны. 🔵Для микросервисов, серверлес-функций и batch-задач. 🔵Для контейнеров и облачных сред с оплатой по потреблению. 👉 @java_geek

🔍 Завтра тестовое собеседование с Java-разработчиком 2 июля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседов
🔍 Завтра тестовое собеседование с Java-разработчиком 2 июля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Сергею Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2Vtzqwfa2Fy

🧠 Зачем использовать @Transactional(readOnly = true)? Многие добавляют @Transactional(readOnly = true) на сервисные методы просто по привычке. Но давайте разберёмся, что на самом деле даёт этот флаг, и где он реально ускоряет выполнение. 📌 Что делает readOnly = true? * Подсказывает JPA провайдеру (например, Hibernate), что изменения в сущностях можно не отслеживать (skip dirty checking). * В некоторых БД может выставить read-only transaction flag, который предотвращает нежелательные изменения (например, в PostgreSQL). * Может ускорить выборки, особенно при больших графах сущностей. 💡 Пример:

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    @Transactional(readOnly = true)
    public UserDto getUser(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new EntityNotFoundException("User not found"));
        return UserDto.from(user);
    }
}
⚠️ Важно: * readOnly = true не блокирует изменения в БД, если вы явно вызываете save() — это НЕ защита от дурака. * Hibernate всё равно создаст транзакцию — это не аннотация "без транзакций". ✅ Когда использовать: * Методы, которые только читают данные и не модифицируют сущности. * Большие выборки без нужды в lazy-инициализации через сессию. * Там, где критична производительность чтения. ❌ Когда НЕ нужно: * Если вы всё равно модифицируете сущности внутри метода. * Если работаете с @Modifying запросами — Spring их игнорирует при readOnly = true. 📎 Документация Spring @Transactional 👉 @java_geek

Fluent Interface Fluent Interface (Текучий интерфейс) — это шаблон проектирования, который позволяет создавать код, читающийс
Fluent Interface Fluent Interface (Текучий интерфейс) — это шаблон проектирования, который позволяет создавать код, читающийся как текст на естественном языке. Он достигается путем создания методов, которые возвращают ссылку на this объект, позволяя вызывать их в цепочке. 👉 @java_geek

👩‍💻🎯 Юнитесты на Java: как новичку поймать баги за 5 Секунд? Приглашаем на открытый урок. 🗓 24 июня в 20:00 МСК 🆓 Беспла
👩‍💻🎯 Юнитесты на Java: как новичку поймать баги за 5 Секунд? Приглашаем на открытый урок. 🗓 24 июня в 20:00 МСК 🆓 Бесплатно. Урок в рамках старта курса «Java-разработчик». 🦾 Тестирование — суперсила разработчика. Научитесь писать код, который проверяет сам себя, экономит часы на отладке и делает ваши приложения неуязвимыми. О чём поговорим: ✔️ Что такое Unit-тесты? Для чего они нужны, даже если «код и так работает». ✔️ JUnit 5 для новичков: как установить и написать первый тест. ✔️ Тестирование = Дзен-кодинг: как тесты помогают понять свой код лучше вас самих. ✔️ Ловушки и лайфхаки: что делать, если тесты падают? Кому будет интересно: Начинающим Java-разработчикам, студентам и всем, кто хочет перестать бояться слов «тестирование» и «баги». В результате вебинара вы: Создадите свой первый тест на Java, поймёте, как тестировать методы с исключениями, и начнёте писать код, которым можно гордиться. 🔗 Ссылка на регистрацию: https://vk.cc/cMXt49 Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

🧠 Почему @Transactional не работает? Один из самых частых вопросов: "Я поставил @Transactional, но транзакция не откатывается. Почему?" 📌 Ответ — в механизме прокси Spring. Spring оборачивает бины с @Transactional в прокси, которые перехватывают вызовы и управляют транзакцией. Но работает это только при вызове метода извне. Если ты вызываешь метод с @Transactional внутри того же класса, прокси не используется, и аннотация игнорируется. 💡 Пример:

@Service
public class UserService {
    public void registerUser() {
        createUser(); // ❌ Транзакция не работает!
    }

    @Transactional
    public void createUser() {
        // изменения в БД
    }
}
📎 Решения: 1. Вынести метод в другой бин:

@Service
public class UserService {
    private final UserWriter writer;

    public UserService(UserWriter writer) {
        this.writer = writer;
    }

    public void registerUser() {
        writer.createUser(); // ✅ работает
    }
}

@Service
public class UserWriter {
    @Transactional
    public void createUser() {
        // изменения в БД
    }
}
2. Или вызвать себя через `ApplicationContext`:

@Autowired
private ApplicationContext context;

public void registerUser() {
    context.getBean(UserService.class).createUser(); // ✅ работает
}
⚠️ Но лучше использовать первый способ — он чище архитектурно. 👉 @java_geek