ru
Feedback
Java Geek

Java Geek

Открыть в Telegram

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

Больше
2 379
Подписчики
-424 часа
-107 дней
-3430 день
Привлечение подписчиков
август '26
август '26
+5
в 1 каналах
июль '26
+8
в 0 каналах
Get PRO
июнь '26
+6
в 0 каналах
Get PRO
май '26
+23
в 0 каналах
Get PRO
апрель '26
+12
в 0 каналах
Get PRO
март '26
+18
в 0 каналах
Get PRO
февраль '26
+21
в 0 каналах
Get PRO
январь '26
+16
в 0 каналах
Get PRO
декабрь '25
+11
в 0 каналах
Get PRO
ноябрь '25
+43
в 32 каналах
Get PRO
октябрь '25
+31
в 0 каналах
Get PRO
сентябрь '25
+55
в 37 каналах
Get PRO
август '25
+40
в 0 каналах
Get PRO
июль '25
+60
в 28 каналах
Get PRO
июнь '25
+61
в 20 каналах
Get PRO
май '25
+71
в 45 каналах
Get PRO
апрель '25
+102
в 37 каналах
Get PRO
март '25
+96
в 38 каналах
Get PRO
февраль '25
+81
в 32 каналах
Get PRO
январь '25
+98
в 34 каналах
Get PRO
декабрь '24
+86
в 35 каналах
Get PRO
ноябрь '24
+75
в 33 каналах
Get PRO
октябрь '24
+89
в 30 каналах
Get PRO
сентябрь '24
+121
в 29 каналах
Get PRO
август '24
+49
в 18 каналах
Get PRO
июль '24
+45
в 0 каналах
Get PRO
июнь '24
+68
в 24 каналах
Get PRO
май '24
+65
в 19 каналах
Get PRO
апрель '24
+48
в 0 каналах
Get PRO
март '24
+78
в 21 каналах
Get PRO
февраль '24
+85
в 18 каналах
Get PRO
январь '24
+154
в 24 каналах
Get PRO
декабрь '23
+111
в 24 каналах
Get PRO
ноябрь '23
+92
в 17 каналах
Get PRO
октябрь '23
+111
в 18 каналах
Get PRO
сентябрь '23
+108
в 0 каналах
Get PRO
август '23
+73
в 0 каналах
Get PRO
июль '23
+99
в 0 каналах
Get PRO
июнь '23
+95
в 0 каналах
Get PRO
май '23
+115
в 0 каналах
Get PRO
апрель '23
+114
в 0 каналах
Get PRO
март '23
+29
в 0 каналах
Get PRO
февраль '23
+67
в 0 каналах
Get PRO
январь '23
+124
в 0 каналах
Get PRO
декабрь '22
+161
в 0 каналах
Get PRO
ноябрь '22
+107
в 0 каналах
Get PRO
октябрь '22
+277
в 0 каналах
Get PRO
сентябрь '22
+1 189
в 0 каналах
Дата
Привлечение подписчиков
Упоминания
Каналы
26 августа0
25 августа0
24 августа0
23 августа0
22 августа0
21 августа0
20 августа0
19 августа+1
18 августа+1
17 августа0
16 августа0
15 августа0
14 августа+1
13 августа0
12 августа0
11 августа0
10 августа0
09 августа0
08 августа0
07 августа0
06 августа0
05 августа0
04 августа0
03 августа+2
02 августа0
01 августа0
Посты канала
В чем отличия между TreeSet и HashSet? Основное отличие между TreeSet и HashSet заключается в том, что TreeSet хранит элемент
В чем отличия между TreeSet и HashSet? Основное отличие между TreeSet и HashSet заключается в том, что TreeSet хранит элементы в отсортированном порядке, в то время как порядок хранения элементов в HashSet не определен. TreeSet также обеспечивает быстрый поиск и извлечение элементов в отсортированном порядке. 📲 Мы в MAX 👉 @java_geek

2
🏗 System Design: Эволюция архитектуры от 1 до 1 000 000 пользователей Главная ошибка разработчиков при проектировании систем - строить звездолет для поездки за хлебом. Микросервисы, Kafka и Kubernetes не нужны вашему стартапу в первый день. Архитектура должна эволюционировать шаг за шагом. Вот как выглядит этот путь. Уровень 1: Одинокий Волк (1 - 1000 юзеров) Всё крутится на одном сервере (например, в DigitalOcean или AWS EC2). • Что там: Ваше Java-приложение (Monolith) + база данных (PostgreSQL) + веб-сервер (Nginx) живут на одной машине. • Плюсы: Развертывание занимает 5 минут, всё работает быстро (сетевые задержки нулевые). • Минусы: Если сервер упал - упало всё. Масштабировать можно только покупкой более мощного процессора/памяти (Вертикальное масштабирование). Уровень 2: Разделение труда (10 000 юзеров) Приложение начинает тормозить, потому что СУБД "съела" всю оперативную память. • Что делаем: Выносим базу данных на отдельный сервер. Желательно использовать управляемое решение (Managed DB от облачного провайдера), чтобы не возиться с бэкапами. • Результат: Приложение и БД больше не дерутся за ресурсы. Уровень 3: Горизонтальное масштабирование (100 000 юзеров) Трафик растет. Один сервер приложения больше не справляется с HTTP-запросами. • Что делаем: Ставим Load Balancer (Балансировщик нагрузки) и поднимаем 3-5 одинаковых серверов с вашим Java-приложением. • Правило: Ваше приложение должно стать Stateless (без состояния). Вы больше не можете хранить сессии пользователей в локальной памяти (RAM), иначе юзер залогинится на Сервере 1, а следующий запрос попадет на Сервер 2, и его "выкинет". Сессии уезжают в централизованное хранилище. Уровень 4: Спасаем базу данных (500 000 юзеров) Приложений много, а БД одна. Она начинает "задыхаться" от количества чтений. • Что делаем (Кэш): Ставим Redis или Memcached. До 80% запросов в типичном приложении - это чтение одних и тех же данных. Кэш отдает их за миллисекунды. • Что делаем (Репликация): Разделяем БД на Master (для записи) и несколько Slave/Replica (только для чтения). Уровень 5: Асинхронность и Очереди (1 000 000+ юзеров) Пользователи жалуются, что загрузка отчета или обработка видео занимает слишком много времени, а HTTP-соединения отваливаются по таймауту. • Что делаем: Внедряем брокер сообщений (Kafka или RabbitMQ) и создаем воркеры. • Как это работает: Юзер жмет "сгенерировать отчет". Приложение кидает задачу в Kafka и мгновенно отвечает юзеру: "В процессе". А фоновые серверы-воркеры не спеша забирают задачи из очереди и делают тяжелую работу. 🧠 Главный принцип System Design Не усложняйте систему до тех пор, пока метрики не покажут, что текущий уровень больше не справляется. Каждое усложнение (Load Balancer, Redis, Kafka) несет за собой новые проблемы: инвалидация кэша, задержки сети, дублирование сообщений. #SystemDesign #Architecture #Backend #Scaling 📲 Мы в MAX 👉 @java_geek
134
3
🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин https://max.ru/channel_win_sysadmin Системный Администратор Windows https://max.ru/channel_linux_admin Linux: Системный администратор https://max.ru/channel_linuxmod Linux https://max.ru/channel_i_linux Системный администратор https://max.ru/channel_devopslib DevOps, SRE, Sysadmin https://max.ru/channel_devops_star DevOps Star (Звезда Девопса) Excel лайфхак 📌 https://t.me/Excel_lifehack Excel лайфхак Английский с нуля 🇬🇧 https://max.ru/UchuEnglish 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С https://max.ru/channel_DevLab1C 1С:Предприятие 8 Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика https://max.ru/channel_cpp_geek C++ geek Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Rust📌 https://max.ru/channel_rust_lib Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика https://max.ru/channel_java_geek Java Geek GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии в IT📌 https://max.ru/progjob https://max.ru/channel_rabotait Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Городские📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП https://max.ru/channel_krasnodar_novosty Краснодар Новости https://max.ru/channel_novosibirsk_novosti Новосибирск https://max.ru/channel_samara_novosti Новости Самары https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга https://max.ru/channel_kazan_novosti Новости Казани https://max.ru/channel_omsk_novosti Новости Омска https://max.ru/channel_moskva_24 Москва 24
112
4
🏗 Java: Структурная конкурентность. Прощайте, зомби-потоки! Допустим, вы используете Виртуальные потоки (Project Loom), чтобы сделать два независимых запроса: получить данные пользователя (API 1) и его заказы (API 2). Раньше мы использовали ExecutorService или CompletableFuture. Но у них есть огромная архитектурная дыра: они ничего не знают друг о друге. 🧟‍♂️ Проблема зомби-потоков (Unstructured Concurrency) Если API 1 мгновенно падает с ошибкой 500, ваш метод все равно будет ждать, пока API 2 доработает (или упадет по таймауту). Поток, качающий заказы, становится "сиротой". Он делает бесполезную работу, тратит сеть и память, хотя результат уже никому не нужен. А если ошибку выкинет родительский метод? Дочерние потоки продолжат жить своей жизнью в фоне. Это хаос. 🧩 Решение: StructuredTaskScope В современной Java (начиная с 21 версии) потоки привязали к лексической области видимости - блоку кода. Если мы выходим из блока (из-за ошибки или успешного завершения), все запущенные внутри него дочерние потоки автоматически отменяются (получают interrupt). Вот как выглядит "Запрос-Ответ", где должны выполниться оба действия (Стратегия *All or Nothing*): // ShutdownOnFailure: если один упал, отменяем остальные try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { // Запускаем подзадачи (Subtasks) Subtask<User> user = scope.fork(() -> fetchUser(id)); Subtask<List<Order>> orders = scope.fork(() -> fetchOrders(id)); scope.join(); // Ждем завершения обеих задач... scope.throwIfFailed(); // ...или первой же ошибки! // Сюда дойдем, только если обе задачи успешны return new UserProfile(user.get(), orders.get()); } // При выходе из блока любые зависшие потоки будут убиты 🏎 Стратегия "Кто первый, тот и прав" А что, если вам нужно получить курс валют, и у вас есть 3 разных провайдера? Вам нужен ответ от любого, кто ответит быстрее. // ShutdownOnSuccess: первый успешный отменяет остальные try (var scope = new StructuredTaskScope.ShutdownOnSuccess<Quote>()) { scope.fork(() -> getFromBankA()); scope.fork(() -> getFromBankB()); scope.fork(() -> getFromBankC()); scope.join(); // Ждем первого успешного return scope.result(); // Возвращаем самый быстрый ответ } Как только Банк А ответит, запросы к Банкам B и C будут немедленно отменены. Никакого ручного управления Future.cancel(). Всё работает из коробки. 🧠 Почему это меняет всё? 1. Читаемость: Многопоточный код читается сверху вниз, как обычный синхронный. 2. Безопасность ресурсов: Утечки потоков физически невозможны. Структура гарантирует, что родитель не завершится, пока не разберется со всеми детьми. 3. Идеальные логи: Стек-трейс теперь показывает реальную иерархию (кто кого вызвал), а не обрывается на внутренностях пула потоков. В связке с Виртуальными потоками это делает Java одним из самых удобных языков для написания высоконагруженных сетевых приложений. #Concurrency #ProjectLoom #CleanCode #Backend 📲 Мы в MAX 👉 @java_geek
136
5
🚀 Java на стероидах: Запуск за 0.05 сек с GraalVM Native Image Главный аргумент хейтеров Java: "Она жирная и медленная на старте". И они правы. JVM нужно время, чтобы прогреться, загрузить классы и скомпилировать байт-код (JIT). Для микросервисов в Kubernetes или Serverless (AWS Lambda) это критично. Но GraalVM Native Image превращает ваше Java-приложение в нативный бинарник. Без JVM. Без java -jar. Просто исполняемый файл. 🏎 JIT vs AOT: В чем разница? 1. Standard JVM (JIT - Just In Time): Вы запускаете код -> JVM интерпретирует его -> находит "горячие участки" -> компилирует их в машинный код прямо во время работы. • Плюс: Максимальная производительность на длинной дистанции (Runtime Optimization). • Минус: Медленный старт, жрет память на компилятор. 2. Native Image (AOT - Ahead Of Time): Вы компилируете код заранее. Весь "мертвый" код выкидывается. Остается только то, что реально используется. • Плюс: Мгновенный старт (< 100ms), мизерное потребление памяти. • Минус: Долгая сборка (build time), нет оптимизаций во время выполнения. 🛠 Как это выглядит на практике? В Spring Boot 3 поддержка Native Image встроена официально. 1. Добавляем плагин (Gradle): plugins { id("org.springframework.boot") version "3.2.0" id("org.graalvm.buildtools.native") version "0.9.28" } 2. Собираем: ./gradlew nativeCompile Внимание: Идите пить кофе. Сборка займет от 2 до 10 минут. GraalVM проводит статический анализ всего вашего кода и всех библиотек. 3. Запускаем: ./build/native/nativeCompile/my-app > Started MyApp in 0.048 seconds (JVM running for 0.052) Да, вы не ослышались. Spring Boot поднимается за 50 миллисекунд. ⚠️ Подводные камни (The Pain Points) Не всё так радужно. Native Image ненавидит динамику. 1. Reflection API: GraalVM должен знать обо всех классах, которые вы загружаете через рефлексию, на этапе сборки. Раньше нужно было писать тонны JSON-конфигов. Сейчас Spring Boot делает это за вас, но сторонние либы могут сломаться. 2. Resources: Если вы читаете файл из src/main/resources не стандартным способом, его может не оказаться в бинарнике. 3. Нет "Write Once, Run Anywhere": Бинарник под Linux не запустится на Windows. Сборку нужно делать в той же OS (или в Docker-контейнере), где будет работать код. 📊 Когда использовать? ✅ Serverless (AWS Lambda, Google Cloud Run): Холодный старт больше не проблема. ✅ CLI утилиты: Консольные тулзы на Java теперь работают мгновенно. ✅ Kubernetes (Scale to Zero): Поды поднимаются и умирают за секунды, экономя ресурсы. ⛔ Обычные микросервисы (High Load): Если сервис живет месяцами и молотит тысячи запросов в секунду, обычная JVM (JIT) обгонит Native Image по пропускной способности (Throughput) за счет рантайм-оптимизаций. #GraalVM #NativeImage #JavaPerformance #SpringBoot3 #Serverless 📲 Мы в MAX 👉 @java_geek
158
6
🐳 Java Testing: Хватит мокать базы данных! Вы всё еще используете H2 для тестов, а в продакшене стоит PostgreSQL? Или, может быть, вы поднимаете docker-compose руками перед запуском mvn test? ⛔ Как было раньше Раньше нам приходилось делать трюки с @DynamicPropertySource, чтобы вручную прокинуть jdbc:url, username и password из поднятого контейнера в контекст Spring. // Old School (Java 17 / Boot 2.7) @DynamicPropertySource static void registerPgProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgres::getJdbcUrl); registry.add("spring.datasource.username", postgres::getUsername); // ... куча ручного кода } ✅ Как сейчас @ServiceConnection сама понимает, что это за контейнер (Postgres, Redis, Kafka, RabbitMQ), и автоматически прописывает нужные свойства в ваш application.properties на время теста. @Testcontainers @SpringBootTest class OrderIntegrationTest { // 1. Объявляем контейнер @Container @ServiceConnection // 👈 Вся магия тут! static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine"); @Autowired private OrderRepository repository; @Test void shouldSaveOrder() { // 2. Тест работает с РЕАЛЬНОЙ базой в Docker var order = new Order("item-123", BigDecimal.TEN); repository.save(order); assertThat(repository.findAll()).hasSize(1); } } Писать контейнер в каждом тестовом классе - дурной тон (и медленно, так как Docker будет стартовать каждый раз заново). В Spring Boot 3.1 появился паттерн TestConfiguration, который позволяет переиспользовать контейнеры. Создаем один файл конфигурации: @TestConfiguration(proxyBeanMethods = false) public class ContainersConfig { @Bean @ServiceConnection public PostgreSQLContainer<?> postgresContainer() { return new PostgreSQLContainer<>("postgres:16-alpine"); } @Bean @ServiceConnection public KafkaContainer kafkaContainer() { return new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.4.0")); } } Теперь в любом тесте просто импортируем этот конфиг: @Import(ContainersConfig.class) @SpringBootTest class AnyIntegrationTest { ... } Вы можете использовать этот же конфиг, чтобы запустить само приложение локально с поднятыми контейнерами! Больше не нужно настраивать локальный Postgres. В папке src/test/java создайте класс для запуска: public class TestApplication { public static void main(String[] args) { SpringApplication.from(MyRealApplication::main) .with(ContainersConfig.class) // Подключаем наши контейнеры .run(args); } } Запускаете TestApplication -> Spring сам поднимает Docker-контейнеры -> приложение коннектится к ним -> вы работаете. 🏁 Итог • Изоляция: Каждый прогон тестов - чистая среда. • Честность: Тестируйте на том, что будет в продакшене. • Удобство: @ServiceConnection убрал весь бойлерплейт. #SpringTest #Testcontainers #Java #DevOps #Docker 📲 Мы в MAX 👉 @java_geek
183
7
🕵️ Бенчмарк как оружие массового поражения, разработка по Mechanical Sympathy и Java после Loom Это лишь часть докладов конференции JVM Day, которые пройдут 29 августа в штаб-квартире Т-Банка в Москве. На ивенте соберутся представители JVM-комьюнити: разрабы, тимлиды, архитекторы и другие спецы, которые работают с Java, Kotlin и Scala. Среди спикеров конфы: 🔴Андрей Кулешов из Яндекса разберет, что произошло в мире JVM-языков за первую половину 2026 года. 🔴Сергей Петрелевич из Т-Банка расскажет, как принципы Mechanical Sympathy и готовые библиотеки помогают ускорить стандартное Spring Boot MVC-приложение. 🔴Александр Ланцов из Мир Plat.Form выступит с докладом о том, насколько после Loom стали удобнее и применимее разные подходы к построению конкурентных программ. Закончится конференция афтепати во дворе штаб-квартиры Т-Банка с играми, PowerPoint Party, открытым микрофоном с историями ошибок и диджей-сетами на виниле под открытым небом. Послушать лекции и заодно посмотреть на офис Т-Банка можно тут. 📲 Мы в MAX 👉 @java_geek
199
8
Array vs ArrayList Выбор между Array (стандартным Java-массивом) и ArrayList зависит от специфики задачи на Java, которую тре
Array vs ArrayList Выбор между Array (стандартным Java-массивом) и ArrayList зависит от специфики задачи на Java, которую требуется решить. Помните о следующих особенностях этих типов: ☕️ Array имеет фиксированный размер и память для него выделяется в момент объявления, а размер ArrayList может динамически изменяться; ☕️ Массивы Java работают гораздо быстрее, а в ArrayList намного проще добавлять/удалять элементы; ☕️ При работе с Array велика вероятность получить ошибку ArrayIndexOutOfBoundsException; ☕️ У ArrayList только одно измерение, а вот массивы Java могут быть многомерными. 👉 @java_geek
172
9
Почему ты получаешь отказ после "норм собеса"? Дело не в знаниях - ты просто не знаешь, что реально проверяют на собеседовани
Почему ты получаешь отказ после "норм собеса"? Дело не в знаниях - ты просто не знаешь, что реально проверяют на собеседованиях Отсюда:  — непонимание, какие навыки надо качать, чтобы выйти на следующий грейд  — ощущение стагнации и отсутствие роста в скиллах  — долгое время на одной и той же зп Решение — знать, что от тебя ждёт интервьюер, и умение правильно донести свою мысль Для этого ребята из ШОРТКАТ (менторской программы для разработчиков) собрали в один файл ОТВЕТЫ НА 50 СЛОЖНЫХ ВОПРОСОВ с Java-собеседований 🔥 Они проанализировали более 100 мок-интервью и собрали внутри реальные вопросы + ответы сильного кандидата Забрать можно бесплатно (!) в боте — @shortcut_sh_bot Переходите по ссылке выше и забирайте файл, чтобы быстрее выйти на новый уровень ☝️ Реклама. О рекламодателе.
187
10
🔒 Java Sealed Classes: Диктатура в вашей иерархии Раньше в Java у нас было всего два стула для классов: 1. Public: Наследуйся кто хочет (открытый проходной двор). 2. Final: Никто не пройдет (полная изоляция). Но что, если я хочу разрешить наследование только моим классам Circle и Square, но запретить Васе из соседнего отдела создавать свой кривой Triangle? Начиная с Java 17, у нас есть Sealed Classes. 🚧 Как это работает? Вы используете ключевое слово sealed и permits, чтобы явно перечислить, кому дозволено быть вашим наследником. public sealed interface PaymentResult permits Success, Failure, Pending { } Теперь компилятор гарантирует: в мире существуют только три вида PaymentResult. Четвертого не дано. 🤝 Идеальная пара: Sealed + Records Чаще всего наследниками делают record, потому что они идеально подходят для хранения данных. public record Success(String txId) implements PaymentResult {} public record Failure(String error) implements PaymentResult {} public record Pending(long timestamp) implements PaymentResult {} 🧠 Главная фишка: Умный Switch (Pattern Matching) Зачем нам эти ограничения? Ради исчерпываемости (Exhaustiveness). Когда вы используете sealed классы в новых switch (Java 21+), компилятор знает все возможные варианты. Вам не нужно писать default ветку! String message = switch (result) { case Success s -> "Paid! ID: " + s.txId(); case Failure f -> "Error: " + f.error(); case Pending p -> "Wait..."; // Нет default! И это безопасно. }; В чем магия? Если через полгода вы добавите в permits новый вариант Cancelled, ваш код перестанет компилироваться везде, где используется этот switch. Компилятор ткнет вас носом: "Ты забыл обработать новый статус!". Это спасает от сотен багов в сложной бизнес-логике. 📜 Три правила для наследников Наследник sealed класса обязан выбрать одну из трех стратегий: 1. final: На мне иерархия заканчивается (как в Records). 2. sealed: Я продолжаю жесткий контроль, вот мои наследники. 3. non-sealed: Я открываю шлюзы - от меня может наследоваться кто угодно (возврат к старому поведению). 🚀 Итог: Используйте Sealed Classes, когда ваша модель данных представляет собой конечное множество вариантов: 🔴Статусы заказа 🔴Типы пользователей (Admin, User, Guest) 🔴Результаты операций (Success, Error) Это делает код предсказуемым и безопасным на уровне компилятора. #Java17 #Architecture #CleanCode #PatternMatching 📲 Мы в MAX 👉 @java_geek
206
11
🕵️ Java var: Удобный сахар или скрытая угроза? С выходом Java 10 ключевое слово var позволило нам писать меньше кода. var - это Local Variable Type Inference. Это значит, что Java осталась строго типизированным языком, просто теперь компилятор сам догадывается о типе переменной, глядя на то, что находится справа от знака равно (=). Но иногда его догадки могут вас удивить. Вот 3 примера, где var работает неочевидно. 1. Ловушка "Diamond Operator" (<>) Самая частая ошибка новичков. // Без var (Классика) List<String> list = new ArrayList<>(); // Компилятор видит слева List<String> и понимает, что справа тоже String. // С var (Ошибка) var list = new ArrayList<>(); В чем проблема? У компилятора нет информации о типе. Он видит пустые скобки <> и решает, что это ArrayList<Object>. В итоге вы теряете типизацию: list.add("Hello"); list.add(123); // ✅ Это сработает, хотя вы, вероятно, хотели только строки! ✅ Как исправить: Если используете var с конструктором, всегда указывайте тип справа: var list = new ArrayList<String>(); 2. Магия "Пересечения типов" (Intersection Types) А вот это уже высший пилотаж, который часто встречается при использовании List.of() или Map.of(). Что будет, если сложить в список данные разных типов? var magicList = List.of(10, 20.5, "30"); // Какой тут тип списка? List<Object>? На самом деле компилятор выведет наиболее специфичный общий тип. Тип переменной magicList будет выглядеть примерно так: List<? extends Serializable & Comparable<? extends Serializable & Comparable<?>>> Java находит общие интерфейсы для Integer, Double и String (все они реализуют Serializable и Comparable) и создает этот ужасный тип-франкенштейн. Это работает, но может свести с ума вашу IDE или методы, принимающие конкретные типы. 3. Анонимные классы на стероидах var позволяет делать трюк, невозможный ранее: сохранять тип анонимного класса. var user = new Object() { String name = "Alex"; int age = 25; }; // Это работает! System.out.println(user.name); System.out.println(user.age); Если бы мы написали Object user = ..., поля name и age были бы недоступны. А var "видит" реальную структуру анонимного объекта. Это иногда полезно для локальных промежуточных вычислений, заменяя DTO или кортежи. 🧠 Золотое правило использования var хорош тогда, когда тип очевиден из правой части: 🔴👍 var users = Map.of("id", 1); (Понятно, что это Map) 🔴👍 var stream = list.stream(); (Понятно, что Stream) 🔴👎 var result = service.process(); (Что вернулось? boolean? User? null?) Читаемость кода важнее краткости! 📲 Мы в MAX 👉 @java_geek
254
12
🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин https://max.ru/channel_win_sysadmin Системный Администратор Windows https://max.ru/channel_linux_admin Linux: Системный администратор https://max.ru/channel_linuxmod Linux https://max.ru/channel_i_linux Системный администратор https://max.ru/channel_devopslib DevOps, SRE, Sysadmin https://max.ru/channel_devops_star DevOps Star (Звезда Девопса) Excel лайфхак 📌 https://t.me/Excel_lifehack Excel лайфхак Английский с нуля 🇬🇧 https://max.ru/UchuEnglish 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С https://max.ru/channel_DevLab1C 1С:Предприятие 8 Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика https://max.ru/channel_cpp_geek C++ geek Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Rust📌 https://max.ru/channel_rust_lib Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика https://max.ru/channel_java_geek Java Geek GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии в IT📌 https://max.ru/progjob https://max.ru/channel_rabotait Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Городские📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП https://max.ru/channel_krasnodar_novosty Краснодар Новости https://max.ru/channel_novosibirsk_novosti Новосибирск https://max.ru/channel_samara_novosti Новости Самары https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга https://max.ru/channel_kazan_novosti Новости Казани https://max.ru/channel_omsk_novosti Новости Омска https://max.ru/channel_moskva_24 Москва 24
218
13
⚔️ Java Battle: List.of() vs Arrays.asList() - в чем разница? На код-ревью часто можно увидеть, как эти два метода используют взаимозаменяемо. На первый взгляд, результат один - список элементов. Но под капотом это два совершенно разных зверя. Давайте разберем, почему замена одного на другой может сломать ваш код. 1. Иллюзия неизменяемости (The Mutability Trap) Это самое важное различие. 🔴List.of() (Java 9+): Создает по-настоящему неизменяемый список. Вы не можете ни добавить, ни удалить, ни изменить элемент. 🔴Arrays.asList() (Java 1.2+): Создает список фиксированного размера, который "обернут" вокруг массива. Вы не можете менять размер (add/remove), но можете заменять элементы! var legacyList = Arrays.asList("A", "B"); var modernList = List.of("A", "B"); legacyList.set(0, "C"); // ✅ РАБОТАЕТ! Список теперь ["C", "B"] modernList.set(0, "C"); // ❌ Ошибка: UnsupportedOperationException legacyList.add("D"); // ❌ Ошибка (размер фиксирован) modernList.add("D"); // ❌ Ошибка (полная иммутабельность) 2. Отношение к null 🔴Arrays.asList: Разрешает null элементы. 🔴List.of: Враждебен к null. Если попытаетесь передать null, мгновенно получите NullPointerException. Это сделано специально, чтобы избежать ошибок в логике. 3. Связь с исходным массивом (Reference vs Copy) Если вы создаете список из существующего массива: String[] arr = {"One", "Two"}; var list1 = Arrays.asList(arr); var list2 = List.of(arr); arr[0] = "Zero"; // Меняем исходный массив System.out.println(list1); // ["Zero", "Two"] <- Изменился вслед за массивом! System.out.println(list2); // ["One", "Two"] <- Остался прежним Arrays.asList работает как "окно" (view) в массив. List.of создает защитную копию данных. 🏁 Итог 🔴Используйте List.of() в 99% случаев. Это безопаснее, быстрее и потребляет меньше памяти. 🔴Используйте Arrays.asList(), только если вам нужны null-ы или вы намеренно хотите, чтобы изменения в исходном массиве отражались в списке (редкий кейс). #Java #CodeTips #InterviewQuestions #JavaCore 📲 Мы в MAX 👉 @java_geek
269
14
🔴 Завтра тестовое собеседование с Java-разработчиком 5 августа(уже завтра!) в 19:00 по мск приходи онлайн на открытое собесе
🔴 Завтра тестовое собеседование с Java-разработчиком 5 августа(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Сергею Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. О рекламодателе.
270
15
☕️ Лямбды и Функциональные интерфейсы: Как это работает под капотом? Мы все любим лямбды в Java за краткость. Но задумывались ли вы, как строго типизированная Java понимает запись x -> x * 2, не зная типа переменной x? Все дело в Функциональных интерфейсах. Давайте разберем механику, которая превращает "бойлерплейт" в элегантный код. 🧩 Что такое SAM? В основе лежит концепция SAM (Single Abstract Method). Функциональный интерфейс - это интерфейс, у которого есть ровно один абстрактный метод. Лямбда-выражение - это не самостоятельный объект. Это ленивая реализация этого самого единственного метода "на лету". 🔥 До vs После Взгляните, как функциональный интерфейс Predicate<T> убивает лишний шум: // ❌ До Java 8 (Анонимный класс) // Куча лишнего кода ради одной проверки Predicate<String> isLong = new Predicate<String>() { @Override public boolean test(String s) { return s.length() > 5; } }; // ✅ С Лямбдой // Компилятор видит Predicate -> ищет метод test -> подставляет логику Predicate<String> isLong = s -> s.length() > 5; ⚙️ Магия invokedynamic Многие думают, что лямбда - это просто "сахар" для анонимных классов. Это не так! 💜 Анонимный класс создает реальный .class файл на диске при компиляции. 💜 Лямбда использует инструкцию байт-кода invokedynamic. Она связывает метод динамически только когда это нужно. 👉 Итог: Меньше мусора в памяти и быстрее загрузка приложения. 📚 Шпаргалка: "Великолепная четверка" В java.util.function есть интерфейсы на все случаи жизни. Запомните базу: 1. Predicate<T> ➜ boolean 💜 Суть: Проверка условия (фильтры). 💜 Пример: stream().filter(x -> x > 0) 2. Consumer<T> ➜ void 💜 Суть: Потребитель. Что-то делает с объектом, ничего не возвращая. 💜 Пример: list.forEach(System.out::println) 3. Function<T, R> ➜ R 💜 Суть: Преобразователь. Берет T, возвращает R. 💜 Пример: stream().map(User::getName) 4. Supplier<T> ➜ T 💜 Суть: Поставщик. Ничего не принимает, отдает объект. 💜 Пример: Optional.orElseGet(() -> new User()) 💡Всегда ставьте аннотацию @FunctionalInterface над своими интерфейсами. Это защитит от случайного добавления второго абстрактного метода, который сломает все лямбды в проекте. 📲 Мы в MAX 👉 @java_geek
276
16
🚀 Hibernate: Эффективное обновление с @DynamicUpdate Часто ли вы задумывались, почему Hibernate при обновлении одного поля в сущности генерирует SQL-запрос, который включает все поля? Это может быть неэффективно, особенно для сущностей с десятками колонок. Именно здесь на помощь приходит аннотация @DynamicUpdate! 💡 В чем проблема? (Без @DynamicUpdate) По умолчанию, когда вы вызываете repository.save(entity) для существующей сущности, Hibernate генерирует UPDATE запрос, который устанавливает значения для всех полей, кроме первичного ключа. // Without @DynamicUpdate update employee set age=?, // даже если только age изменился first_name=?, //... и это тоже last_name=? where id=? Если изменилось только age, остальные поля обновляются на те же значения, что были. ✨ Решение: @DynamicUpdate(true) Если вы добавите @DynamicUpdate к вашей сущности, Hibernate будет генерировать SQL-запрос UPDATE, который включает только те поля, которые были изменены (dirty-checking) с момента загрузки или создания сущности. Смотрим на код: @Entity @DynamicUpdate // ✨ Добавляем эту аннотацию! public class Employee extends AbstractPersistable<Long> { @Column String firstName; @Column String lastName; @Column Integer age; // ... } // В EmployeeService: // var entity = employeeRepository.findById(1L).get(); // entity.setAge(22); // Изменили только возраст // employeeRepository.save(entity); Сгенерированный SQL: // With @DynamicUpdate update employee set age=? // ✅ Обновляется ТОЛЬКО измененное поле where id=? ⚖️ Когда использовать? - Используйте, если у вас большие сущности (много колонок) и вы часто обновляете только небольшую часть полей. Это сэкономит трафик и немного ускорит базу данных. - Имейте в виду, что Hibernate придется динамически строить SQL-запрос при каждом обновлении, что может добавить небольшой оверхед, но обычно выгода от оптимизации SQL его перевешивает. Сделайте ваш код более чистым и эффективным! 🛠️ ❓ А вы используете @DynamicUpdate в своих проектах? Поделитесь в комментариях! 👇 P.S. Не путайте с @DynamicInsert, который делает то же самое для INSERT запросов (включает только не-null поля). 📲 Мы в MAX 👉 @java_geek
315
17
Что такое пул строк? Это набор строк, хранящийся в Heap. ☕ Пул строк возможен благодаря неизменяемости строк в Java и реализации идеи интернирования строк; ☕ Пул строк помогает экономить память, но по этой же причине создание строки занимает больше времени; ☕ Когда для создания строки используются ", то сначала ищется строка в пуле с таким же значением, если находится, то просто возвращается ссылка, иначе создается новая строка в пуле, а затем возвращается ссылка на неё; ☕ При использовании оператора new создаётся новый объект String. Затем при помощи метода intern() эту строку можно поместить в пул или же получить из пула ссылку на другой объект String с таким же значением; ☕ Пул строк является примером паттерна «Приспособленец» (Flyweight). 📲 Мы в MAX 👉 @java_geek
561
18
🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. https://max.ru/tipsysdmin Типичный Сисадмин https://max.ru/channel_win_sysadmin Системный Администратор Windows https://max.ru/channel_linux_admin Linux: Системный администратор https://max.ru/channel_linuxmod Linux https://max.ru/channel_i_linux Системный администратор https://max.ru/channel_devopslib DevOps, SRE, Sysadmin https://max.ru/channel_devops_star DevOps Star (Звезда Девопса) Excel лайфхак 📌 https://t.me/Excel_lifehack Excel лайфхак Английский с нуля 🇬🇧 https://max.ru/UchuEnglish 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С https://max.ru/channel_DevLab1C 1С:Предприятие 8 Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика https://max.ru/channel_cpp_geek C++ geek Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Rust📌 https://max.ru/channel_rust_lib Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика https://max.ru/channel_java_geek Java Geek GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии в IT📌 https://max.ru/progjob https://max.ru/channel_rabotait Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
292
19
Что такое «сессия»? Сессия — это сеанс связи между клиентом и сервером, устанавливаемый на определенное время. Сеанс устанавливается непосредственно между клиентом и веб-сервером в момент получения первого запроса к веб-приложению. Каждый клиент устанавливает с сервером свой собственный сеанс, который сохраняется до окончания работы с приложением. 📲 Мы в MAX 👉 @java_geek
314
20
Зачем нужен HashMap, если есть Hashtable? ☕ Методы класса Hashtable синхронизированы, что приводит к снижению производительности, а HashMap - нет; ☕ HashTable не может содержать элементы null, тогда как HashMap может содержать один ключ null и любое количество значений null; ☕ Iterator у HashMap, в отличие от Enumeration у HashTable, работает по принципу «fail-fast» (выдает исключение при любой несогласованности данных). Hashtable это устаревший класс и его использование не рекомендовано. 👉 @java_geek
443