es
Feedback
Библиотека Java разработчика

Библиотека Java разработчика

Ir al canal en Telegram

📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP

Mostrar más

📈 Análisis del canal de Telegram Библиотека Java разработчика

El canal Библиотека Java разработчика (@bookjava) en el segmento lingüístico de Ruso es un actor destacado. Actualmente la comunidad reúne a 10 278 suscriptores, ocupando la posición 12 030 en la categoría Tecnologías y Aplicaciones y el puesto 63 913 en la región Rusia.

📊 Métricas de audiencia y dinámica

Desde su creación el невідомо, el proyecto ha mostrado un crecimiento acelerado, reuniendo a 10 278 suscriptores.

Según los últimos datos del 05 junio, 2026, el canal mantiene una actividad estable. En los últimos 30 días la variación de miembros fue de 20, y en las últimas 24 horas de 0, conservando un alto alcance.

  • Estado de verificación: No verificado
  • Tasa de interacción (ER): El promedio de interacción de la audiencia es 8.29%. Durante las primeras 24 horas tras publicar, el contenido suele obtener 3.77% de reacciones respecto al total de suscriptores.
  • Alcance de las publicaciones: Cada publicación recibe en promedio 852 visualizaciones. En el primer día suele acumular 388 visualizaciones.
  • Reacciones e interacción: La audiencia responde de forma activa: el promedio de reacciones por publicación es 6.
  • Intereses temáticos: El contenido se centra en temas clave como string, интерфейс, строка, boot, api.

📝 Descripción y política de contenido

El autor describe el recurso como un espacio para expresar opiniones subjetivas:
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP

Gracias a la alta frecuencia de actualizaciones (últimos datos recibidos el 07 junio, 2026), el canal mantiene la vigencia y un amplio alcance. La analítica demuestra que la audiencia interactúa activamente con el contenido, lo que lo convierte en un punto de referencia dentro de la categoría Tecnologías y Aplicaciones.

10 278
Suscriptores
Sin datos24 horas
+27 días
+2030 días
Archivo de publicaciones
🤖 Хотите автоматизировать инфраструктуру для тестирования прямо в Gradle? На открытом уроке «Облако в кармане: запускаем всю
🤖 Хотите автоматизировать инфраструктуру для тестирования прямо в Gradle? На открытом уроке «Облако в кармане: запускаем всю инфраструктуру для теста при сборке» от OTUS мы расскажем, как избежать ручных настроек и запусков. Вместо этого вы научитесь автоматизировать весь процесс с помощью Docker, DockerCompose и TestContainers, интегрируя их с Gradle. Урок полезен для разработчиков на Kotlin и Java, которые работают с автотестами — интеграционными и end-to-end. В ходе урока вы освоите: ▫️Автоматический запуск всей необходимой инфраструктуры для тестирования. ▫️Создание Docker-образов для тестов и деплоя. ▫️Разработку автотестов, которые поднимут ваши навыки на новый уровень. Участники получат скидку на курс «Kotlin Backend Developer. Professional». ➡️ Встречаемся 29 апреля в 20:00 МСК, регистрация открыта: https://vk.cc/cL78v6 Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

🧠 JPA: подводный камень с @ElementCollection и fetch = FetchType.EAGER Сегодня покажу, почему @ElementCollection(fetch = Fet
🧠 JPA: подводный камень с @ElementCollection и fetch = FetchType.EAGER Сегодня покажу, почему @ElementCollection(fetch = FetchType.EAGER) — скрытая угроза производительности и неожиданного поведения. 📌 Суть проблемы При использовании @ElementCollection с EAGER Hibernate делает отдельный SELECT на каждую коллекцию, даже при JOIN FETCH на родительскую сущность.

@Entity
class User {
    @Id Long id;

    @ElementCollection(fetch = FetchType.EAGER)
    List<String> tags;
}
Запрос findAll() приведёт к N+1 проблеме: 1 запрос на User, потом по одному на каждый tags. 💡 Почему это больно Даже если вы используете JOIN FETCH на User, Hibernate не может сделать JOIN на @ElementCollection. Это ограничение — Hibernate всегда грузит коллекцию отдельным запросом. ⚠️ Особенно опасно при pagination Если вы делаете Page<User> — Hibernate сначала грузит User'ов, а затем делает N запросов на коллекции. В проде это быстро становится проблемой. ✅ Что делать 1. Делайте fetch = FetchType.LAZY (по умолчанию так и есть). 2. Если нужно подгрузить коллекцию — используйте @BatchSize:

@ElementCollection
@BatchSize(size = 20)
List<String> tags;
Или вручную:

SELECT u FROM User u LEFT JOIN FETCH u.tags WHERE u.id IN :ids
👉 Следи за @ElementCollection — он не так прост, как кажется. 👉@BookJava

🧠 Как избежать N+1 при использовании @OneToMany в JPA Одна из самых коварных ловушек JPA - это N+1 проблема. Особенно часто
🧠 Как избежать N+1 при использовании @OneToMany в JPA Одна из самых коварных ловушек JPA - это N+1 проблема. Особенно часто она проявляется при @OneToMany, например:

@Entity
class Author {
    @OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
    private List<Book> books;
}
Вы загружаете список авторов, а потом проходите по каждому и вызываете getBooks() — и BAM 💥: 1 запрос на авторов и N запросов на книги. 📌 Решение - @EntityGraph или JOIN FETCH Оба варианта решают проблему, но @EntityGraph — декларативный и более гибкий способ:

@EntityGraph(attributePaths = "books")
List<Author> findAll(); // Spring Data JPA
⚡️ Или через JPQL:

@Query("SELECT a FROM Author a JOIN FETCH a.books")
List<Author> findAllWithBooks();
💡 Совет: всегда думайте о графе объектов. Если вам нужно сразу подтянуть связанные сущности — делайте это явно. Не надейтесь на LAZY по умолчанию. ⚠️ Осторожно с пагинацией и JOIN FETCH — могут появиться дубликаты или проблемы с LIMIT. В таких случаях лучше использовать @BatchSize или подзапросы. 👉@BookJava

👩‍💻 Разработка на Java требует глубокого понимания не только языка, но и принципов работы JVM, многопоточности и современны
👩‍💻 Разработка на Java требует глубокого понимания не только языка, но и принципов работы JVM, многопоточности и современных фреймворков. Курс «Java Developer. Professional» — это структурированное обучение для разработчиков, которые хотят выйти на новый уровень, освоить актуальный стек технологий и уверенно претендовать на позиции уровня Middle+. 🦾 Вы получите 96 часов практической работы, обучение на живых вебинарах, вы разберете ключевые аспекты работы JVM, научитесь строить эффективные многопоточные приложения, освоите Spring WebFlux, Kafka, реактивный Postgres и Kubernetes. Программа OTUS постоянно обновляется, соответствуя требованиям рынка, а диплом ценится работодателями. 👉 Пройдите вступительное тестирование и присоединяйтесь к группе: https://vk.cc/cL3cnt 🎁 Начните обучение со скидкой, подробности у менеджеров. ПРОМОКОД: JAVA_04 Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

Чем отличаются checked и unchecked исключения в java? В Java исключения делятся на два основных типа: checked и unchecked. Ра
Чем отличаются checked и unchecked исключения в java? В Java исключения делятся на два основных типа: checked и unchecked. Разница между ними ключевая и касается как обработки, так и структуры кода. ✅ Checked Exceptions (Проверяемые исключения) Примеры: IOException, SQLException, FileNotFoundException Отличия: 1. Проверяются компилятором — вы обязаны либо обработать их с помощью try-catch, либо явно пробросить (throws) в сигнатуре метода. 2. Производные от Exception, но не от RuntimeException. 3. Используются для ситуаций, которые можно разумно ожидать и обработать (например, отсутствие файла, проблемы с сетью). Пример:

public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);  // может выбросить IOException
}
Unchecked Exceptions (Непроверяемые исключения) Примеры: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException Отличия: 1. Не проверяются компилятором — вы не обязаны их обрабатывать или декларировать. 2. Производные от RuntimeException. 3. Возникают в результате ошибок в логике программы или непредвиденных ситуаций. Пример:

public void printLength(String str) {
    System.out.println(str.length());  // может выбросить NullPointerException
}
Если кратко: Checked — ошибки среды, требующие явной обработки. Unchecked — ошибки в логике, ответственность программиста. 👉@BookJava

🧠 JPA: не забывай про flush() перед clear() — иначе словишь баг Если ты используешь EntityManager вручную, например, при батчевой вставке или обновлении, то, скорее всего, пишешь что-то вроде:

for (int i = 0; i < entities.size(); i++) {
    em.persist(entities.get(i));
    if (i % 50 == 0) {
        em.clear(); // чтобы не росла память
    }
}
⚠️ Но тут баг: без flush() перед clear() ты теряешь все неперсистенные изменения! Hibernate просто забудет про них. ✅ Правильно так:

for (int i = 0; i < entities.size(); i++) {
    em.persist(entities.get(i));
    if (i % 50 == 0) {
        em.flush();
        em.clear();
    }
}
📌 flush() гарантирует, что все накопленные изменения пойдут в базу, а clear() уже безопасно очищает контекст. 💡 Эта ошибка особенно коварна, потому что не всегда проявляется — зависит от настроек, триггеров в БД, кэша и т.д. 👉@BookJava

Осталось всего 2 дня — углубитесь в функциональное программирование на Scala в Otus 📢 24 апреля в 20:00 пройдёт открытый веб
Осталось всего 2 дня — углубитесь в функциональное программирование на Scala в Otus 📢 24 апреля в 20:00 пройдёт открытый вебинар с Алексеем Воронцом — руководителем разработки в Naumen, 14 лет опыта, из них 9 лет на Scala. Он расскажет: — почему Scala — функциональный язык — как работать с ключевыми библиотеками — как повысить выразительность кода Если вы уже знакомы со Scala или желаете перейти на него и хотите развивать функциональный подход в своих проектах — этот вебинар для вас. Каждый участник: — сможет задать вопросы эксперту — получит скидку на полный курс по Scala-разработке 👉 Не упустите возможность перейти на новый уровень — регистрируйтесь, осталось 2 дня до начала Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

🧠 Spring Boot и медленные autowire — проверь, не зарыта ли у тебя бомба в @Configuration Есть распространённый анти-паттерн: ты используешь @Configuration и внутри создаёшь бины с @Bean, а в этих методах — инжектишь зависимости через параметры. Всё выглядит красиво и «по фэншую»... но только на первый взгляд.

@Configuration
public class MyConfig {

    @Bean
    public MyService myService(SomeDep dep) {
        return new MyService(dep);
    }

    @Bean
    public SomeDep someDep() {
        return new SomeDep();
    }
}
⚠️ Проблема: такие методы вызываются при старте контекста, и если SomeDep создаётся долго (например, подтягивает настройки из удалённого конфига, делает init-запрос в БД, или тянет секьюрити-контекст), это тормозит весь старт. 📌 Хуже всего, если ты не подозреваешь об этом: ведь @Bean -методы не видны как "инициализация", и кажется, что контекст тормозит "где-то ещё". 💡 Совет: - Используй @Lazy в нужных местах, особенно если bean тяжёлый или редко используется. - Разделяй конфигурацию: отдельно core, отдельно init-heavy. - Не бойся отказаться от @Configuration в пользу @Component + @Service, если это упрощает понимание. И главное — профилируй старт. spring-boot-starter-actuator + --debug могут открыть глаза. 👉@BookJava

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

🧠 Spring Boot 3.2+: ускоряем стартап с помощью application.metrics.export.observation.enabled=false Spring Boot 3.2 по умолчанию включает сбор Micrometer Observation метрик — даже если вы не используете Prometheus, Datadog и пр. Это полезно, но часто избыточно — особенно в микросервисах, где важна скорость старта. 📌 Что это даёт? - Отключает автоконфигурацию ObservationRegistry - Убирает связанные Bean'ы - Сокращает время старта до 30-60% (в зависимости от контекста) 💡 Как применить? В application.yml или application.properties:

management:
  metrics:
    export:
      observation:
        enabled: false
Или так, если используешь .properties:

management.metrics.export.observation.enabled=false
⚠️ Важно: это не отключает другие метрики Micrometer. Это касается только новой подсистемы Observation — она полезна для трассировки, но не всегда нужна. 📎 Документация Micrometer Observation 👉@BookJava

🧠 Lazy Initialization по-взрослому: не создавай проблемы на ровном месте В Spring Boot часто можно встретить вот такую конструкцию:

@Service
public class EmailService {
    private final SmtpClient client = new SmtpClient(); // дорогая инициализация
}
⚠️ Проблема: SmtpClient создаётся сразу при старте приложения. Даже если EmailService ни разу не вызовется. Это не только waste of resources, но и может сломать запуск, если SmtpClient требует специфического окружения. 📌 Решение — ленивая инициализация, но не через старый добрый null-check, а красиво, безопасно и читаемо: 💡 Способ #1: Lazy<T> wrapper

@Component
public class EmailService {
    private final Supplier<SmtpClient> client = Suppliers.memoize(SmtpClient::new);

    public void sendEmail(...) {
        client.get().send(...);
    }
}
Можно и без Guava:

public class Lazy<T> {
    private Supplier<T> supplier;

    public Lazy(Supplier<T> supplier) {
        this.supplier = () -> {
            T value = supplier.get();
            this.supplier = () -> value;
            return value;
        };
    }

    public T get() {
        return supplier.get();
    }
}
💡 Способ #2: через Spring

@Service
public class EmailService {
    private final ObjectProvider<SmtpClient> client;

    public EmailService(ObjectProvider<SmtpClient> client) {
        this.client = client;
    }

    public void sendEmail(...) {
        client.getObject().send(...);
    }
}
🧵 Итог: - Не инициализируй тяжёлые объекты зря. - Используй Supplier, ObjectProvider или Lazy<T>. - Это особенно критично для тестов, лямбд и кэширования. 👉@BookJava

Реальные проекты и нетворкинг с профи: Летняя школа бэкенд‑разработки Яндекса открыла набор Начинающие бэкендеры, есть планы
Реальные проекты и нетворкинг с профи: Летняя школа бэкенд‑разработки Яндекса открыла набор Начинающие бэкендеры, есть планы на лето? Если уже умеете писать читаемый код в Python, Java или C++ и разбираетесь в алгоритмах, Летняя школа бэкенда Яндекса — ваш шанс прокачаться в разработке высоконагруженных сервисов. Вы получите уникальный опыт, работая вместе с ведущими специалистами компании. Как проходит обучение: — со 2 июня по 27 июля — онлайн-лекции, семинары и практические задания — с 28 июля по 24 августа — разработка реальных проектов офлайн или онлайн Вас ждут: — работа в фулстек-командах в коворкингах Яндекса — лекции от специалистов компании в летнем лектории — возможность стать частью команды и получить офер: больше половины выпускников становятся стажерами или сотрудниками компании Школа бесплатная, но нужно пройти отбор. Отправляй заявку до 27 апреля!

🧠 Сейчас покажу баг, который легко пропустить при работе с @Transactional в Spring Boot 3+. 📌 Проблема — транзакция не рабо
🧠 Сейчас покажу баг, который легко пропустить при работе с @Transactional в Spring Boot 3+. 📌 Проблема — транзакция не работает, потому что метод вызывается изнутри того же класса. Рассмотрим пример:

@Service
public class UserService {

    @Transactional
    public void createUser(User user) {
        saveUser(user);
        sendWelcomeEmail(user); // бросает исключение
    }

    public void saveUser(User user) {
        userRepository.save(user);
    }
}
💥 Если sendWelcomeEmail выбросит исключение — транзакция не откатится, потому что @Transactional работает через прокси. Вызов createUser() должен идти извне, чтобы Spring "знал", что нужно обернуть вызов в транзакцию. ✅ Решения: 1. Вынести transactional-метод в отдельный бин:

   @Service
   public class UserCreationService {
       @Transactional
       public void createUser(User user) {
           // ...
       }
   }
   
2. Внедрить self-прокси:

   @Autowired
   private UserService self;

   public void externalCaller(User user) {
       self.createUser(user);
   }
   
3. Использовать AopContext:

   ((UserService) AopContext.currentProxy()).createUser(user);
   
⚠️ Не забудь включить exposeProxy = true в @EnableAspectJAutoProxy. 💡 Современный подход — разделение ответственности: transactional-методы живут в отдельных сервисах, их проще тестировать и не возникает подобных ловушек. 👉@BookJava

Хотите глубже разобраться в функциональном программировании и писать более качественный код на Scala? Приходите на вебинар в
Хотите глубже разобраться в функциональном программировании и писать более качественный код на Scala? Приходите на вебинар в Otus 24 апреля в 20:00 пройдёт открытый вебинар с Алексеем Воронцом — руководителем разработки в Naumen, 14 лет опыта, из них 9 лет на Scala. На практических примерах он покажет: — почему Scala — функциональный язык — как работать с ключевыми библиотеками — как повысить выразительность кода ❗️ Если вы уже знакомы со Scala или только начинаете к нему присматриваться и хотите развивать функциональный подход в своих проектах — этот вебинар для вас. Каждый участник: — сможет задать вопросы эксперту — получит скидку на полный курс по Scala-разработке 👉 Регистрируйтесь и сделайте свой код лучше Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

🧠 Простое ускорение @Transactional методов в Spring Boot Знаете, что @Transactional по умолчанию оборачивает метод в прокси?
🧠 Простое ускорение @Transactional методов в Spring Boot Знаете, что @Transactional по умолчанию оборачивает метод в прокси? Это значит: - Внутренние вызовы в том же классе не проходят через транзакцию; - Каждый такой прокси — это AOP-магия, которую можно обойти ради производительности. 📌 Если вы точно знаете, что метод будет вызываться только извне, и вам не нужна прокси-обёртка — используйте @Transactional на уровне интерфейса и включите interface-based proxy.

@Configuration
@EnableTransactionManagement(proxyTargetClass = false) // JDK proxy
public class TransactionConfig {
}

public interface UserService {
    @Transactional
    void createUser(User user);
}
📉 Это немного снижает overhead, особенно в высоконагруженных сервисах, где сотни тысяч вызовов @Transactional-методов. 💡 Подходит, если: - У вас слоистая архитектура; - Транзакции нужны только снаружи; - Вы не используете вызовы this.someMethod() внутри сервиса. ⚠️ Не забывайте: - JDK Proxy работает только с интерфейсами; - Если вызываете методы внутри того же класса — прокси не сработает (и транзакция не начнётся). 📊 Профильте. Иногда замена proxyTargetClass = true на false даёт +3-5% к throughput. 👉@BookJava

🧠 Как ускорить загрузку контекста Spring Boot — простой приём Если у вас тяжёлый Spring Boot-приложение с кучей конфигураций
🧠 Как ускорить загрузку контекста Spring Boot — простой приём Если у вас тяжёлый Spring Boot-приложение с кучей конфигураций и бинов, время старта может легко вырасти до 20–30 секунд и больше. Сегодня покажу приём, который помогает ускорить cold start за счёт отключения ненужных автоматических конфигураций. 📌 Spring Boot автоконфигурация — это палка о двух концах. Она упрощает старт, но часто тянет за собой кучу лишнего. Особенно если вы используете @SpringBootApplication, которая включает в себя @EnableAutoConfiguration. 💡 Решение — использовать spring.autoconfigure.exclude, чтобы явно выключить ненужное. Например:

# application.yaml
spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
❗️Это особенно актуально: - в микросервисах без UI (отключаем MVC) - если datasource создаётся вручную - в тестах и lightweight-режимах 👀 Как понять, что мешает? 1. Запусти приложение с флагом --debug или логгером org.springframework.boot.autoconfigure уровня DEBUG. 2. Посмотри, какие автоконфигурации "matched", но тебе не нужны. 3. Добавь их в exclude. 🧰 Альтернатива — использовать аннотацию @ImportAutoConfiguration с явным списком нужных автоконфигураций. Это тонкая настройка, идеально для библиотек и SDK. ⚠️ Не переусердствуй: отключение нужной конфигурации может привести к тихим багам. Лучше вырезать по одной и смотреть на эффект. 👉 Это один из способов сделать Spring Boot предсказуемым и быстрым, особенно в CI/CD или serverless-окружениях. 👉@BookJava

👩‍💻 JDBC — ваш швейцарский нож для работы с данными Приглашаем на открытый урок. 🗓 22 апреля в 20:00 МСК 🆓 Бесплатно. Уро
👩‍💻 JDBC — ваш швейцарский нож для работы с данными Приглашаем на открытый урок. 🗓 22 апреля в 20:00 МСК 🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Professional». О чём поговорим: ✔️Основы JDBC: что это такое, зачем нужно и как работает ✔️Практические примеры выполнения сложных запросов ✔️Работа с транзакциями и обработка ошибок в JDBC ✔️ Оптимизация производительности при работе с данными через JDBC Кому будет интересно: Вебинар будет полезен разработчикам, инженерам по базам данных и архитекторам ПО, стремящимся улучшить навыки работы с базами данных и оптимизировать взаимодействие с данными. В результате урока: Вы научитесь эффективно использовать JDBC для работы с базами данных и сможете применять полученные знания в реальных проектах 🔗 Ссылка на регистрацию: https://vk.cc/cKRDCS Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

💡 Ленивая инициализация бинов в Spring Boot — мощный инструмент ускорения старта По умолчанию Spring инициализирует все singleton-бины при запуске приложения. Это может быть проблемой в больших проектах: старт медленный, а половина бинов не нужна сразу. 📌 Как ускорить старт и снизить потребление памяти? — Lazy Init! ✅ Глобально:

spring:
  main:
    lazy-initialization: true
Все бины станут ленивыми — создадутся только при первом обращении. Это может сократить старт приложения на 30-60%! ✅ Локально (избирательно):

@Component
@Lazy
public class HeavyBean {
    public HeavyBean() {
        System.out.println("HeavyBean init...");
    }
}
Или через @Lazy на зависимостях:

@Service
public class MyService {
    public MyService(@Lazy HeavyBean heavyBean) {
        this.heavyBean = heavyBean;
    }
}
🧠 Когда использовать: - В dev-окружении — чтобы ускорить локальный dev cycle. - В CLI/Batch-приложениях, где используется 1-2 бина. - Когда есть тяжёлые бины, не нужные на старте (например, интеграции, большие клиенты и т.п.). ⚠️ Осторожно: - Если забыть @Lazy на зависимостях, Spring всё равно создаст бин. - Некоторые бины должны быть загружены сразу (например, @Scheduled, @EventListener), иначе они не сработают. 👉@BookJava

❓Сталкиваетесь с задачами, когда вам нужно выбрать лучший алгоритм, но не понимаете, как анализировать их сложность? Ваш код
❓Сталкиваетесь с задачами, когда вам нужно выбрать лучший алгоритм, но не понимаете, как анализировать их сложность? Ваш код может быть медленным или неэффективным, и вы не знаете, как это исправить? 📗На открытом вебинаре 21 апреля в 20:00 мск вы освоите важные инструменты для анализа сложности алгоритмов, улучшите свой навык решения алгоритмических задач и на примере простых алгоритмов сортировки и увидите разницу при применении алгоритмов разной степени сложности. ➡️Регистрируйтесь прямо сейчас и получите скидку на большое обучение «C# Developer» по промокоду SHARP_SPEC_4: https://vk.cc/cKRCrB Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

🧠 ThreadLocal — скрытая угроза утечек памяти ThreadLocal — удобный способ хранить данные, привязанные к потоку. Например, дл
🧠 ThreadLocal — скрытая угроза утечек памяти ThreadLocal — удобный способ хранить данные, привязанные к потоку. Например, для SimpleDateFormat или текущего пользователя в рамках запроса. Но с ним легко получить утечку памяти, особенно в thread pool'ах. 📌 Почему? ThreadLocal-хранилище (Thread.threadLocals) живёт столько же, сколько поток. А потоки из пулов живут долго. Если ты забыл вызвать remove() — данные останутся в памяти навсегда. Пример:

private static final ThreadLocal<UserContext> context = ThreadLocal.withInitial(UserContext::new);

public void handleRequest() {
    try {
        context.set(new UserContext("user123"));
        // работа с контекстом
    } finally {
        context.remove(); // ОБЯЗАТЕЛЬНО!
    }
}
⚠️ Что пойдёт не так без remove()? - Поток из пула закончит обрабатывать запрос, но UserContext останется висеть в ThreadLocalMap этого потока. - Если UserContext содержит ссылки на другие объекты (например, HttpSession, EntityManager и т.д.) — вся эта цепочка не будет GC-шиться. - И так накапливается утечка. 💡 Советы: - Всегда вызывай remove() в finally. - Для Spring можно использовать RequestScope или @ControllerAdvice вместо ThreadLocal. - Проверяй код сторонних библиотек, если они используют ThreadLocal, особенно в фильтрах и интерсепторах. 👉@BookJava