"Write Once, Run Anywhere."
Сегодня, спустя 30 лет, он по-прежнему актуален — и не просто маркетинговая фраза.
Вот 10 крутых фактов о Java, которые доказывают:
🔸 1. Java был создан не для компьютеров
Изначально язык назывался Oak и предназначался для умных телевизоров и микроволновок. Но всё изменилось, когда Sun Microsystems увидела потенциал Java для интернета. В 1995 году Oak стал Java — и начал революцию.
---
🔸 2. Java была первым языком, с которым подружился Netscape
В 90-х Java-апплеты позволяли запускать интерактивный код в браузере. Это был первый шаг к веб-приложениям, задолго до появления React и Angular.
---
🔸 3. Android — тоже Java (почти)
До Kotlin и Jetpack Compose весь Android-код писался на Java. Google создал Dalvik VM, совместимую с Java-синтаксисом. Даже сейчас Java остаётся одним из основных языков в Android-разработке.
---
🔸 4. Java работает в биржах, банках и… спутниках
Крупнейшие финансовые системы (Goldman Sachs, NASDAQ, VISA) используют Java на своих серверах. А ещё Java-код был на борту космического аппарата NASA Deep Space 1.
---
🔸 5. Java запускается более 50 миллиардов раз в день
По оценкам Oracle, JVM стартует 50+ миллиардов раз ежедневно — в приложениях, микросервисах, Android-программах, банках и даже игровых серверах Minecraft.
---
🔸 6. В Java можно писать без `new` и `null`
Благодаря modern-фичам:
record
, var
, sealed
, pattern matching
, и проектам как Loom (виртуальные потоки) — Java стала элегантнее, лаконичнее и безопаснее.---
🔸 7. JVM умеет исполнять не только Java
Scala, Kotlin, Groovy, Clojure, Jython — всё это языки, которые работают поверх JVM. Java стала платформой, а не просто языком.
---
🔸 8. Java 21 — это уже не та Java, что в универе
С выпуском Java 21 добавлены:
- Виртуальные потоки (вместо сложного `ExecutorService`)
- Pattern Matching
- Sequenced collections
- Record-массивы
- Scoped values
Теперь Java ближе к Go и Rust по лаконичности, но с тем же надёжным фундаментом.
---
🔸 9. Java — язык с лучшей обратной совместимостью
Код, написанный 20 лет назад, всё ещё компилируется и запускается. Ни один другой язык не может этим похвастаться на таком уровне.
---
🔸 10. Java — не мертва. Она на стероидах
На GitHub Java стабильно в топ-5.
Oracle, RedHat, Amazon, BellSoft, JetBrains — все инвестируют в развитие OpenJDK.
Появляются фреймворки: Quarkus, Micronaut, Helidon — Java теперь быстрая и лёгкая, как Node.js.
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
☕ JEP 512: Поддержка структурированных массивов в Java
Java готовится к мощному обновлению — структурированные массивы (structured arrays) придут в язык и улучшат работу с плотными, кэш-эффективными структурами данных!
🧬 Что такое структурированные массивы?
Это массивы, где данные объектов хранятся не как ссылки, а в смежной памяти, как в `C`/`C++`/Rust. Это позволяет:
• 📦 Упаковать данные компактно, без разрывов
• 🚀 Повысить кэш-локальность и производительность
• 🔬 Избежать лишних аллокаций и GC overhead
🔧 Пример:
📈 Зачем это нужно?
✅ Быстрее в high-performance системах (игры, машинное обучение, базы данных)
✅ Простой способ писать "низкоуровневый" код на Java без перехода на JNI
✅ Поддержка value-классов (Project Valhalla) на новом уровне
📅 Статус и планы:
JEP 512 пока в статусе "Proposed to Target" для Java 23. Это часть большого проекта Valhalla, направленного на улучшение модели памяти и данных в JVM.
💬 Впереди Java с реальными структурами, а не объектами-ссылками. Оптимизация данных выходит на новый уровень!
📖 Подробнее: https://openjdk.org/jeps/512
@javatg
Java готовится к мощному обновлению — структурированные массивы (structured arrays) придут в язык и улучшат работу с плотными, кэш-эффективными структурами данных!
🧬 Что такое структурированные массивы?
Это массивы, где данные объектов хранятся не как ссылки, а в смежной памяти, как в `C`/`C++`/Rust. Это позволяет:
• 📦 Упаковать данные компактно, без разрывов
• 🚀 Повысить кэш-локальность и производительность
• 🔬 Избежать лишних аллокаций и GC overhead
🔧 Пример:
value class Vec3 {
float x, y, z;
}
Vec3[] arr = new Vec3[1000]; // Под капотом — плотно упакованный блок памяти!
📈 Зачем это нужно?
✅ Быстрее в high-performance системах (игры, машинное обучение, базы данных)
✅ Простой способ писать "низкоуровневый" код на Java без перехода на JNI
✅ Поддержка value-классов (Project Valhalla) на новом уровне
📅 Статус и планы:
JEP 512 пока в статусе "Proposed to Target" для Java 23. Это часть большого проекта Valhalla, направленного на улучшение модели памяти и данных в JVM.
💬 Впереди Java с реальными структурами, а не объектами-ссылками. Оптимизация данных выходит на новый уровень!
📖 Подробнее: https://openjdk.org/jeps/512
@javatg
🧠 Java-задача: "Immutable? Не совсем…"
📜 Условие:
У тебя есть якобы *immutable* класс:
И следующий код:
❓ Вопрос:
1. Могут ли быть выведены "x = 1, y = 0" или даже "x = 0, y = 0"?
2. Почему?
3. Как гарантировать корректность и видимость всех полей в многопоточной среде?
⚠️ Подвох:
- В Java Memory Model (`JMM`) даже `final` поля не дают полной гарантии видимости, если объект передаётся между потоками без синхронизации.
- Поток
- Конструктор не завершился, а
- Это не баг JVM, а результат слабых гарантий
✅ Правильный ответ:
Да, такой результат возможен —
🛡️ Как защититься:
- Сделать
- Передавать объект через synchronized блоки,
🎯 Чему учит задача:
• Знание Java Memory Model (JMM)
• Понимание, что
• Почему даже "immutable" объекты могут стать "опасно mutating"
• Умение писать багоустойчивый многопоточный код
@javatg
📜 Условие:
У тебя есть якобы *immutable* класс:
public class Point {
public final int x;
public final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
И следующий код:
public class Main {
static Point shared;
public static void main(String[] args) throws InterruptedException {
Thread writer = new Thread(() -> {
shared = new Point(1, 2);
});
Thread reader = new Thread(() -> {
Point p = shared;
if (p != null) {
System.out.println("x = " + p.x + ", y = " + p.y);
}
});
writer.start();
writer.join();
reader.start();
reader.join();
}
}
❓ Вопрос:
1. Могут ли быть выведены "x = 1, y = 0" или даже "x = 0, y = 0"?
2. Почему?
x
и y
ведь final
— разве этого недостаточно? 3. Как гарантировать корректность и видимость всех полей в многопоточной среде?
⚠️ Подвох:
- В Java Memory Model (`JMM`) даже `final` поля не дают полной гарантии видимости, если объект передаётся между потоками без синхронизации.
- Поток
reader
может увидеть частично сконструированный объект:- Конструктор не завершился, а
shared
уже указывает на объект.- Это не баг JVM, а результат слабых гарантий
JMM
без синхронизации.✅ Правильный ответ:
Да, такой результат возможен —
reader
может увидеть x = 1
, y = 0
, или даже x = 0
, y = 0
.🛡️ Как защититься:
- Сделать
shared
volatile, или- Передавать объект через synchronized блоки,
Lock
, AtomicReference
, CountDownLatch
, Thread-safe очередь
, и т.д.
static volatile Point shared;
🎯 Чему учит задача:
• Знание Java Memory Model (JMM)
• Понимание, что
final != synchronized
• Почему даже "immutable" объекты могут стать "опасно mutating"
• Умение писать багоустойчивый многопоточный код
@javatg
🧱 Собираем OpenJDK сами? Лови инструменты от Blackslate!
Если ты хочешь *собрать свою версию OpenJDK* или поэкспериментировать с оптимизациями JVM — тебе сюда:
👉 [Полный список тулов от Blackslate](https://www.blackslate.io/tech-stack/tools-to-build-openjdk)
🔧 Что внутри:
• [JDKBuild](https://github.com/blackslateio/jdkbuild) — фреймворк для сборки JDK из исходников, поддерживает разные версии и платформы.
• Builder Docker Images — набор docker-контейнеров, уже готовых к сборке JDK.
• Patch Tools — инструменты для управления патчами к JDK, удобно тестировать свои изменения.
• Releases — собранные дистрибутивы, если не хочешь собирать сам.
🔥 Особенности:
• Много версий: от Java 8 до Java 21
• Локальная и CI/CD сборка
• Поддержка кастомных патчей и расширений
• Кроссплатформенность: Linux, macOS, Windows
👨🔧 Идеально, если ты:
• Тюнишь JVM под свой продукт
• Создаёшь минималистичный JDK под контейнеры
• Хочешь изучить, как всё устроено внутри
https://www.blackslate.io/tech-stack/tools-to-build-openjdk
@javatg
Если ты хочешь *собрать свою версию OpenJDK* или поэкспериментировать с оптимизациями JVM — тебе сюда:
👉 [Полный список тулов от Blackslate](https://www.blackslate.io/tech-stack/tools-to-build-openjdk)
🔧 Что внутри:
• [JDKBuild](https://github.com/blackslateio/jdkbuild) — фреймворк для сборки JDK из исходников, поддерживает разные версии и платформы.
• Builder Docker Images — набор docker-контейнеров, уже готовых к сборке JDK.
• Patch Tools — инструменты для управления патчами к JDK, удобно тестировать свои изменения.
• Releases — собранные дистрибутивы, если не хочешь собирать сам.
🔥 Особенности:
• Много версий: от Java 8 до Java 21
• Локальная и CI/CD сборка
• Поддержка кастомных патчей и расширений
• Кроссплатформенность: Linux, macOS, Windows
👨🔧 Идеально, если ты:
• Тюнишь JVM под свой продукт
• Создаёшь минималистичный JDK под контейнеры
• Хочешь изучить, как всё устроено внутри
https://www.blackslate.io/tech-stack/tools-to-build-openjdk
@javatg
⚙️ Какие инструменты нужны, чтобы собрать OpenJDK?
OpenJDK — это не просто Java. Это сложный проект на C++, Bash, Autoconf и make-файлах. Чтобы собрать его из исходников, одного JDK недостаточно.
🧰 Вот ключевые инструменты, необходимые для сборки OpenJDK:
• 🛠️ Boot JDK — для сборки вам нужен уже установленный JDK (на одну версию младше).
• 🧱 Build system — OpenJDK использует
• 🧪 Toolchain — компиляторы (GCC или Clang), утилиты вроде
• 🐧 Build OS — Linux предпочтителен, но поддерживаются и macOS/Windows.
• ⚙️ Доп. инструменты —
💡 Подсказка: для большинства Linux-дистрибутивов можно установить всё необходимое с помощью system package manager.
🧪 Пример команды:
🔗 Полный список и инструкции:
https://www.blackslate.io/tech-stack/tools-to-build-openjdk
Сборка OpenJDK — это крутой способ заглянуть под капот Java-машины. Если ты девелопер уровня "пощупать байт-код" — это must try.
@javatg
OpenJDK — это не просто Java. Это сложный проект на C++, Bash, Autoconf и make-файлах. Чтобы собрать его из исходников, одного JDK недостаточно.
🧰 Вот ключевые инструменты, необходимые для сборки OpenJDK:
• 🛠️ Boot JDK — для сборки вам нужен уже установленный JDK (на одну версию младше).
• 🧱 Build system — OpenJDK использует
make
и autoconf
. • 🧪 Toolchain — компиляторы (GCC или Clang), утилиты вроде
zip
, unzip
, tar
, bash
, awk
. • 🐧 Build OS — Linux предпочтителен, но поддерживаются и macOS/Windows.
• ⚙️ Доп. инструменты —
freetype
, cups
, alsa
, devtoolset
(для старых OS), pkg-config
.💡 Подсказка: для большинства Linux-дистрибутивов можно установить всё необходимое с помощью system package manager.
🧪 Пример команды:
sudo apt install build-essential autoconf zip unzip \
libx11-dev libxext-dev libxrender-dev libxtst-dev \
libxt-dev libasound2-dev libcups2-dev libfreetype6-dev
🔗 Полный список и инструкции:
https://www.blackslate.io/tech-stack/tools-to-build-openjdk
Сборка OpenJDK — это крутой способ заглянуть под капот Java-машины. Если ты девелопер уровня "пощупать байт-код" — это must try.
@javatg
Большие данные — большие возможности!
🚀 Хотите освоить Spark и научиться разрабатывать продвинутые ML-модели, анализировать временные ряды и строить мощные data-архитектуры?
Курс «Spark Developer» от OTUS — это практический путь к глубинному пониманию Spark. Вы научитесь запускать Spark в Hadoop и Kubernetes, разрабатывать коннекторы, обрабатывать потоковые и табличные данные, а также настраивать мониторинг Spark-приложений.
Наши преподаватели – практикующие эксперты, а диплом OTUS ценится в ведущих компаниях.
После обучения вы сможете разрабатывать Spark-приложения, интегрировать их с различными источниками данных и запускать их в продакшн.Пора действовать!
➡️ Пройдите вступительное тестирование и воспользуйтесь скидкой на обучение по промокоду Early_Spark_5 (до 10 июня включительно): https://tglink.io/428ad13ecce1?erid=2W5zFGVsaBi
#реклама
О рекламодателе
🚀 Хотите освоить Spark и научиться разрабатывать продвинутые ML-модели, анализировать временные ряды и строить мощные data-архитектуры?
Курс «Spark Developer» от OTUS — это практический путь к глубинному пониманию Spark. Вы научитесь запускать Spark в Hadoop и Kubernetes, разрабатывать коннекторы, обрабатывать потоковые и табличные данные, а также настраивать мониторинг Spark-приложений.
Наши преподаватели – практикующие эксперты, а диплом OTUS ценится в ведущих компаниях.
После обучения вы сможете разрабатывать Spark-приложения, интегрировать их с различными источниками данных и запускать их в продакшн.Пора действовать!
➡️ Пройдите вступительное тестирование и воспользуйтесь скидкой на обучение по промокоду Early_Spark_5 (до 10 июня включительно): https://tglink.io/428ad13ecce1?erid=2W5zFGVsaBi
#реклама
О рекламодателе
📡 TM-SGNL — Android-приложение для анализа сигналов слежки
Разработано независимым журналистом Micah Lee, это Android-приложение помогает обнаруживать возможные попытки слежки через радиочастотные сигналы. Основано на идеи мониторинга внезапных всплесков в радиодиапазоне, когда телефон переходит в активное взаимодействие (например, при включении микрофона, отправке данных и пр.).
🔍 Основные функции:
▪ Детекция RF-активности через внешние RTL-SDR USB-устройства
▪ Визуализация сигналов в режиме спектрограммы
▪ Поддержка анализа GSM, LTE, Wi-Fi и других диапазонов
▪ Не требует root-доступа
📱 Приложение построено на базе Android + USB-хост API, используется совместно с RTL-SDR донглом через OTG. Отлично подойдёт для тех, кто занимается цифровой безопасностью, OSINT, активизмом или просто хочет знать, что происходит в эфире вокруг.
🔗 GitHub: https://github.com/micahflee/TM-SGNL-Android
@javatg
Разработано независимым журналистом Micah Lee, это Android-приложение помогает обнаруживать возможные попытки слежки через радиочастотные сигналы. Основано на идеи мониторинга внезапных всплесков в радиодиапазоне, когда телефон переходит в активное взаимодействие (например, при включении микрофона, отправке данных и пр.).
🔍 Основные функции:
▪ Детекция RF-активности через внешние RTL-SDR USB-устройства
▪ Визуализация сигналов в режиме спектрограммы
▪ Поддержка анализа GSM, LTE, Wi-Fi и других диапазонов
▪ Не требует root-доступа
📱 Приложение построено на базе Android + USB-хост API, используется совместно с RTL-SDR донглом через OTG. Отлично подойдёт для тех, кто занимается цифровой безопасностью, OSINT, активизмом или просто хочет знать, что происходит в эфире вокруг.
🔗 GitHub: https://github.com/micahflee/TM-SGNL-Android
@javatg
🧠 Задача с подвохом для Java-разработчиков
Что выведет следующий код?
Варианты ответа:
1️⃣ Компилируется, выводит
2️⃣ Ошибка компиляции
3️⃣ Исключение времени выполнения
4️⃣ Выведет
💡 Подсказка:
Метод
✅ Ответ: 3
На строке `items.add("Clojure")` выбрасывается `UnsupportedOperationException`.
Чтобы избежать этой ловушки, создавай изменяемый список явно:
List<String> items = new ArrayList<>(Arrays.asList("Java", "Kotlin", "Scala"));
@javatg
Что выведет следующий код?
public class ListMystery {
public static void main(String[] args) {
List<String> items = Arrays.asList("Java", "Kotlin", "Scala");
items.set(1, "Groovy");
items.add("Clojure"); // строка №5
System.out.println(items);
}
}
Варианты ответа:
1️⃣ Компилируется, выводит
[Java, Groovy, Scala, Clojure]
2️⃣ Ошибка компиляции
3️⃣ Исключение времени выполнения
4️⃣ Выведет
[Java, Groovy, Scala]
— метод add
проигнорирован💡 Подсказка:
Метод
Arrays.asList()
не создаёт обычный ArrayList
, а возвращает фиксированную обёртку над массивом. Размер менять нельзя.✅ Ответ: 3
На строке `items.add("Clojure")` выбрасывается `UnsupportedOperationException`.
Чтобы избежать этой ловушки, создавай изменяемый список явно:
List<String> items = new ArrayList<>(Arrays.asList("Java", "Kotlin", "Scala"));
@javatg
🔐 Управление JWT-токенами с помощью библиотеки Auth0 Java JWT
Если ты работаешь с аутентификацией и безопасностью в Java-приложениях, тебе пригодится библиотека от [Auth0](https://github.com/auth0/java-jwt) для работы с JWT.
📌 Что такое JWT?
JWT (JSON Web Token) — это стандарт, позволяющий безопасно передавать данные между участниками как JSON-объекты. Он используется для авторизации, верификации пользователей и обмена данными без сессий.
🧰 Auth0 Java JWT позволяет:
- Генерировать токены с кастомными claim'ами
- Подписывать токены с помощью HMAC или RSA
- Валидировать и декодировать токены
- Проверять срок действия (exp), аудиторию, субъект и прочее
🧪 Пример: генерация токена
🔍 Проверка и декодирование токена
🛡️ Преимущества:
- Простота API
- Хорошая поддержка и документация
- Безопасное управление ключами и подписями
📚 Статья с примерами и пояснениями:
👉 https://www.blackslate.io/articles/manage-jwt-
Если ты пишешь backend на Java и работаешь с авторизацией — эта библиотека точно стоит твоего внимания.
@javatg
Если ты работаешь с аутентификацией и безопасностью в Java-приложениях, тебе пригодится библиотека от [Auth0](https://github.com/auth0/java-jwt) для работы с JWT.
📌 Что такое JWT?
JWT (JSON Web Token) — это стандарт, позволяющий безопасно передавать данные между участниками как JSON-объекты. Он используется для авторизации, верификации пользователей и обмена данными без сессий.
🧰 Auth0 Java JWT позволяет:
- Генерировать токены с кастомными claim'ами
- Подписывать токены с помощью HMAC или RSA
- Валидировать и декодировать токены
- Проверять срок действия (exp), аудиторию, субъект и прочее
🧪 Пример: генерация токена
Algorithm algorithm = Algorithm.HMAC256("secret");
String token = JWT.create()
.withIssuer("auth0")
.withClaim("userId", 123)
.withExpiresAt(new Date(System.currentTimeMillis() + 3600_000))
.sign(algorithm);
🔍 Проверка и декодирование токена
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("auth0")
.build();
DecodedJWT jwt = verifier.verify(token);
System.out.println(jwt.getClaim("userId").asInt());
🛡️ Преимущества:
- Простота API
- Хорошая поддержка и документация
- Безопасное управление ключами и подписями
📚 Статья с примерами и пояснениями:
👉 https://www.blackslate.io/articles/manage-jwt-
Если ты пишешь backend на Java и работаешь с авторизацией — эта библиотека точно стоит твоего внимания.
@javatg
Релиз через два дня. Код готов. Почти...
Остались тесты. Ну, точнее — покрытие. Потому что QA уже дышит в затылок, а ты сидишь и выбираешь: спать или корпеть до утра.
Explyt Test умеет создавать тесты под твой код — сам. Быстро. В IDE. Без плясок.
Хочешь, чтобы релиз прошёл, а не пролетел? Попробуй бесплатно! 👉 explyt.ai
Остались тесты. Ну, точнее — покрытие. Потому что QA уже дышит в затылок, а ты сидишь и выбираешь: спать или корпеть до утра.
Explyt Test умеет создавать тесты под твой код — сам. Быстро. В IDE. Без плясок.
Хочешь, чтобы релиз прошёл, а не пролетел? Попробуй бесплатно! 👉 explyt.ai
🚀 Spring WebFlux with Server-Sent Events 🚀
Повышайте интерактивность своих приложений с помощью Spring WebFlux и Server-Sent Events (SSE)! 🔥
• Что такое Server-Sent Events?
SSE — механизм, позволяющий серверу «толкать» данные клиенту по одному направлению (сервер → браузер) через постоянное HTTP-соединение. Идеально подходит для оповещений, обновлений статуса, live-лент и любых реальных данных, где не требуется двунаправленный сокет.
• Почему WebFlux + SSE?
• 🌀 *Реактивная модель*
WebFlux построен на реактивных потоках (`Flux`/`Mono`), что позволяет обрабатывать тысячи параллельных соединений с минимальным использованием ресурсов.
• ⏱️ *Низкая задержка*
Вместо опроса (polling) клиент сразу получает новые события, как только сервер их публикует.
• ⚙️ *Простота интеграции*
Spring WebFlux предоставляет готовые абстракции для SSE, достаточно вернуть
• Пример простого контроллера SSE в Spring WebFlux
• Здесь Flux.interval() генерирует последовательность чисел каждую секунду.
• Мы формируем ServerSentEvent<String> с идентификатором id, именем события event и полезными данными data.
• Браузер или любой клиент, подписанный на /sse-stream, будет получать сообщение каждую секунду без повторного HTTP-запроса.
Как использовать на клиенте?
• EventSource автоматически подключается к указанному URL и слушает серверные события.
• Метод addEventListener("tick", ...) обрабатывает только события с именем tick.
• Советы и подводные камни
• ⚠️ Обработка отмены (cancel)
Когда клиент закрывает страницу или отключается, WebFlux автоматически отменит подписку на Flux. При необходимости можно добавить .doOnCancel(...) для логирования или очистки ресурсов.
• 🛠️ Ошибка и повторная попытка (retry)
При сетевых сбоях браузер сам попытается переподключиться к тому же URL. Если вы хотите контролировать логику на сервере, используйте .retry() или .onErrorResume() в потоке Flux.
• 🔒 Безопасность
При необходимости защищайте URL SSE с помощью авторизации (JWT, OAuth2) или rate-limit’а, чтобы злоумышленники не «залили» ресурс.
• 📈 Масштабирование
Благодаря реактивной модели WebFlux вы можете легко масштабировать приложение на Kubernetes, не опасаясь, что сотни SSE-потоков «съедят» память и потоки.
• Где применить?
• Живые обновления статуса задач и билдов (CI/CD, DevOps)
• Чат-сообщения или лента комментариев в режиме «реального времени»
• Мониторинг метрик и дашборды (оперативные алерты)
• Финансовые или спортивные котировки (ticker, live scores)
• Оповещения об изменениях в БД (CDC), когда нужен асинхронный пуш
@javatg
Повышайте интерактивность своих приложений с помощью Spring WebFlux и Server-Sent Events (SSE)! 🔥
• Что такое Server-Sent Events?
SSE — механизм, позволяющий серверу «толкать» данные клиенту по одному направлению (сервер → браузер) через постоянное HTTP-соединение. Идеально подходит для оповещений, обновлений статуса, live-лент и любых реальных данных, где не требуется двунаправленный сокет.
• Почему WebFlux + SSE?
• 🌀 *Реактивная модель*
WebFlux построен на реактивных потоках (`Flux`/`Mono`), что позволяет обрабатывать тысячи параллельных соединений с минимальным использованием ресурсов.
• ⏱️ *Низкая задержка*
Вместо опроса (polling) клиент сразу получает новые события, как только сервер их публикует.
• ⚙️ *Простота интеграции*
Spring WebFlux предоставляет готовые абстракции для SSE, достаточно вернуть
Flux<ServerSentEvent<...>>
из контроллера.• Пример простого контроллера SSE в Spring WebFlux
@RestController
public class SseController {
@GetMapping(value = "/sse-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> streamEvents() {
return Flux.interval(Duration.ofSeconds(1))
.map(seq -> ServerSentEvent.<String>builder()
.id(String.valueOf(seq))
.event("tick")
.data("Тик №" + seq)
.build()
);
}
}
• Здесь Flux.interval() генерирует последовательность чисел каждую секунду.
• Мы формируем ServerSentEvent<String> с идентификатором id, именем события event и полезными данными data.
• Браузер или любой клиент, подписанный на /sse-stream, будет получать сообщение каждую секунду без повторного HTTP-запроса.
Как использовать на клиенте?
<script>
const evtSource = new EventSource("/sse-stream");
evtSource.addEventListener("tick", e => {
console.log("Новое событие:", e.data);
// Можно обновлять UI: например, timestamp или счётчик
});
evtSource.onerror = err => console.error("SSE ошибка:", err);
</script>
• EventSource автоматически подключается к указанному URL и слушает серверные события.
• Метод addEventListener("tick", ...) обрабатывает только события с именем tick.
• Советы и подводные камни
• ⚠️ Обработка отмены (cancel)
Когда клиент закрывает страницу или отключается, WebFlux автоматически отменит подписку на Flux. При необходимости можно добавить .doOnCancel(...) для логирования или очистки ресурсов.
• 🛠️ Ошибка и повторная попытка (retry)
При сетевых сбоях браузер сам попытается переподключиться к тому же URL. Если вы хотите контролировать логику на сервере, используйте .retry() или .onErrorResume() в потоке Flux.
• 🔒 Безопасность
При необходимости защищайте URL SSE с помощью авторизации (JWT, OAuth2) или rate-limit’а, чтобы злоумышленники не «залили» ресурс.
• 📈 Масштабирование
Благодаря реактивной модели WebFlux вы можете легко масштабировать приложение на Kubernetes, не опасаясь, что сотни SSE-потоков «съедят» память и потоки.
• Где применить?
• Живые обновления статуса задач и билдов (CI/CD, DevOps)
• Чат-сообщения или лента комментариев в режиме «реального времени»
• Мониторинг метрик и дашборды (оперативные алерты)
• Финансовые или спортивные котировки (ticker, live scores)
• Оповещения об изменениях в БД (CDC), когда нужен асинхронный пуш
@javatg
☕ Задача для опытных Java-разработчиков: «Призрачная утечка памяти в продакшене»
🧠 Уровень: Senior Java / JVM Internals
🎯 Цель: Найти источник утечки памяти в долгоживущем Java-сервисе и объяснить поведение GC
📍 Ситуация:
У вас есть Java-сервис (Spring Boot), который стабильно работает 5–6 часов, а потом начинает резко тормозить.
Мониторинг показывает рост heap usage почти до лимита, несмотря на регулярные GC-сборки.
Интересные факты:
- GC срабатывает часто, но не очищает больше 20–30% хипа
- Не происходит
- Подозрения падают на кэш, но размер кэша — ограничен (Caffeine, maxSize=5000)
- Все коллекции под контролем, слабые ссылки используются
- Нет утечек в логах, нет
🧩 Задача:
1. Где искать утечку, если GC работает, но память не освобождается?
2. Почему слабые ссылки не помогают?
3. Как поведение
4. Какой инструмент использовать для анализа "живых" объектов в памяти?
5. Как бы вы реализовали периодический аудит памяти в проде без перезапуска?
6. Покажи, как сработает
💡 Подсказка:
Некоторые библиотеки (особенно с рефлексией, динамической загрузкой классов и кэшем) создают утечки через неудаляемые ссылки на ClassLoader, особенно в сочетании с
🛠 Решение:
1. Снимаем дамп памяти:
или
2. Анализируем в Eclipse MAT:
- Сортируем объекты по retained size
- Видим
- Причина — статические поля/синглтоны держат ссылки на классы, которые не выгружаются
3. Проверяем код:
- Использовался
- Загруженные классы не выгружались, т.к. на них ссылается пул потоков
4. Решения:
- Использовать
- Вызывать
- Избегать глобальных синглтонов со ссылками на классы, загружаемые динамически
5. Профилактика:
- Включить периодический
- Встроить
📌 Вывод:
Даже при работающем GC утечка возможна, если в памяти удерживаются ссылки через
💬 Идеальный вопрос для собеседования на позицию Java-сеньора с уклоном в JVM-интерны.
@javatg
🧠 Уровень: Senior Java / JVM Internals
🎯 Цель: Найти источник утечки памяти в долгоживущем Java-сервисе и объяснить поведение GC
📍 Ситуация:
У вас есть Java-сервис (Spring Boot), который стабильно работает 5–6 часов, а потом начинает резко тормозить.
Мониторинг показывает рост heap usage почти до лимита, несмотря на регулярные GC-сборки.
Интересные факты:
- GC срабатывает часто, но не очищает больше 20–30% хипа
- Не происходит
OutOfMemoryError
, но приложение начинает "фризить"- Подозрения падают на кэш, но размер кэша — ограничен (Caffeine, maxSize=5000)
- Все коллекции под контролем, слабые ссылки используются
- Нет утечек в логах, нет
Thread`-leak по `jstack
🧩 Задача:
1. Где искать утечку, если GC работает, но память не освобождается?
2. Почему слабые ссылки не помогают?
3. Как поведение
ClassLoader
может влиять на утечку?4. Какой инструмент использовать для анализа "живых" объектов в памяти?
5. Как бы вы реализовали периодический аудит памяти в проде без перезапуска?
6. Покажи, как сработает
jmap
, jcmd
, MAT
или VisualVM
для выявления источника💡 Подсказка:
Некоторые библиотеки (особенно с рефлексией, динамической загрузкой классов и кэшем) создают утечки через неудаляемые ссылки на ClassLoader, особенно в сочетании с
ThreadLocal
, ScheduledExecutorService
, Class.forName
, URLClassLoader
.🛠 Решение:
1. Снимаем дамп памяти:
jmap -dump:format=b,file=heap.bin <PID>
или
jcmd <PID> GC.heap_dump heap.bin
2. Анализируем в Eclipse MAT:
- Сортируем объекты по retained size
- Видим
ThreadLocalMap
, ClassLoader
, Class
→ strong references остаются даже после GC- Причина — статические поля/синглтоны держат ссылки на классы, которые не выгружаются
3. Проверяем код:
- Использовался
Class.forName(...)
в плагин-системе- Загруженные классы не выгружались, т.к. на них ссылается пул потоков
4. Решения:
- Использовать
WeakReference
к загруженным классам- Вызывать
shutdownNow()
и вручную очищать ThreadLocal.remove()
- Избегать глобальных синглтонов со ссылками на классы, загружаемые динамически
5. Профилактика:
- Включить периодический
jcmd GC.class_histogram
- Встроить
/heapdump
endpoint для отладки в проде (под защищённым доступом)📌 Вывод:
Даже при работающем GC утечка возможна, если в памяти удерживаются ссылки через
ThreadLocal
, ClassLoader
, или пула потоков. Это не очевидно и не вызывает OOM, но "раздувает" хип и убивает производительность.💬 Идеальный вопрос для собеседования на позицию Java-сеньора с уклоном в JVM-интерны.
@javatg
💡 Подключение к Minio из Java
Если вы ищете способ работать с объектным хранилищем Minio из Java, то эта статья от BlackSlate — именно то, что вам нужно! Рассмотрим ключевые моменты:
Что такое Minio?
Minio — это высокопроизводительный, S3-совместимый объектный сервер с открытым исходным кодом, который позволяет легко хранить, управлять и извлекать данные. Он отлично подходит для облачных и серверных приложений.
Основные темы статьи:
- Установка и настройка Minio:
Статья описывает, как запустить Minio сервер в локальной или облачной среде. Вы узнаете, как создать пользователя и настроить доступные ключи для подключения.
- Использование Minio Java SDK:
Для работы с Minio из Java необходимо добавить соответствующую зависимость в ваш проект. В статье приведены примеры настройки Maven/Gradle:
- Базовые операции с хранилищем:
Вы научитесь:
- Подключаться к Minio серверу с помощью MinioClient.
- Создавать бакеты.
- Загрузить и скачать объекты.
- Удалять объекты и бакеты.
- Пример кода:
Статья содержит подробный пример кода, демонстрирующий подключение и выполнение базовых операций:
Почему это важно?
Подключение к Minio позволяет разработчикам создавать масштабируемые, гибкие и отказоустойчивые приложения с использованием объектного хранилища. Используя Java SDK, вы получаете простой и понятный API для интеграции с вашим сервисом.
Если вы работаете над проектом, где важны быстрые операции с данными и совместимость с AWS S3 API, то этот подход — отличное решение!
✍️ Читайте полную статью: https://https://www.blackslate.io/articles/connect-to-minio-from-java
@javatg
Если вы ищете способ работать с объектным хранилищем Minio из Java, то эта статья от BlackSlate — именно то, что вам нужно! Рассмотрим ключевые моменты:
Что такое Minio?
Minio — это высокопроизводительный, S3-совместимый объектный сервер с открытым исходным кодом, который позволяет легко хранить, управлять и извлекать данные. Он отлично подходит для облачных и серверных приложений.
Основные темы статьи:
- Установка и настройка Minio:
Статья описывает, как запустить Minio сервер в локальной или облачной среде. Вы узнаете, как создать пользователя и настроить доступные ключи для подключения.
- Использование Minio Java SDK:
Для работы с Minio из Java необходимо добавить соответствующую зависимость в ваш проект. В статье приведены примеры настройки Maven/Gradle:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.3</version>
</dependency>
- Базовые операции с хранилищем:
Вы научитесь:
- Подключаться к Minio серверу с помощью MinioClient.
- Создавать бакеты.
- Загрузить и скачать объекты.
- Удалять объекты и бакеты.
- Пример кода:
Статья содержит подробный пример кода, демонстрирующий подключение и выполнение базовых операций:
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.GetObjectArgs;
// Другие необходимые импорты
public class MinioExample {
public static void main(String[] args) throws Exception {
// Инициализируем клиента с URL, access key и secret key
MinioClient minioClient = MinioClient.builder()
.endpoint("http://127.0.0.1:9000")
.credentials("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY")
.build();
// Создание бакета (если ещё не создан)
boolean bucketExists = minioClient.bucketExists("my-bucket");
if (!bucketExists) {
minioClient.makeBucket("my-bucket");
}
// Загрузка файла в бакет
minioClient.putObject(
PutObjectArgs.builder()
.bucket("my-bucket")
.object("example.txt")
.stream(new FileInputStream("example.txt"), -1, 10485760)
.build()
);
// Скачивание файла из бакета
InputStream stream = minioClient.getObject(
GetObjectArgs.builder()
.bucket("my-bucket")
.object("example.txt")
.build()
);
// Далее можно считать данные из stream...
stream.close();
}
}
Почему это важно?
Подключение к Minio позволяет разработчикам создавать масштабируемые, гибкие и отказоустойчивые приложения с использованием объектного хранилища. Используя Java SDK, вы получаете простой и понятный API для интеграции с вашим сервисом.
Если вы работаете над проектом, где важны быстрые операции с данными и совместимость с AWS S3 API, то этот подход — отличное решение!
✍️ Читайте полную статью: https://https://www.blackslate.io/articles/connect-to-minio-from-java
@javatg
erid: 2W5zFH6MTbv
Канал про собеседования, алгоритмы, System Design, процессы, культуру и инженерию в FAANG/BigTech
Автор канала — разработчик с 18-летним опытом, из которых 8 лет он провёл в FAANG (3,5 года — в Amazon). Работал и жил в России, Германии, Люксембурге и Великобритании, провёл более 100 технических интервью в FAANG-компании.
На канале разбираю реальные задачи с собеседований в FAANG по алгоритмам и System Design. Рассматриваю задачи из не-FAANG компаний на Java, делая акцент на многопоточность. Делюсь опытом работы в FAANG, рассказываю о процессах, технологиях и инженерной культуре, обсуждаю особенности релокации и жизни разработчика в разных странах.
Если вам интересны эти темы, подписывайтесь: www.tg-me.com/faangmaster
Канал про собеседования, алгоритмы, System Design, процессы, культуру и инженерию в FAANG/BigTech
Автор канала — разработчик с 18-летним опытом, из которых 8 лет он провёл в FAANG (3,5 года — в Amazon). Работал и жил в России, Германии, Люксембурге и Великобритании, провёл более 100 технических интервью в FAANG-компании.
На канале разбираю реальные задачи с собеседований в FAANG по алгоритмам и System Design. Рассматриваю задачи из не-FAANG компаний на Java, делая акцент на многопоточность. Делюсь опытом работы в FAANG, рассказываю о процессах, технологиях и инженерной культуре, обсуждаю особенности релокации и жизни разработчика в разных странах.
Если вам интересны эти темы, подписывайтесь: www.tg-me.com/faangmaster
🚀 Java API Tip — Integer.valueOf() и кеширование 🚀
Знаешь ли ты, что
📦 Значения в диапазоне от -128 до 127 кэшируются!
Это значит, что:
Но:
🔍 Почему так?
Чтобы повысить производительность и сэкономить память, Java автоматически кеширует часто используемые значения.
🛠 Кстати, ты можешь изменить границу кеша через JVM-опцию:
📌 Полезно, если у тебя в системе часто используются числа вне стандартного диапазона.
#Java #Performance #JVM #DevTips
@javatg
Знаешь ли ты, что
Integer.valueOf(int)
не всегда создаёт новый объект?📦 Значения в диапазоне от -128 до 127 кэшируются!
Это значит, что:
Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b); // 👉 true (один и тот же объект)
Но:
Integer x = Integer.valueOf(200);
Integer y = Integer.valueOf(200);
System.out.println(x == y); // 👉 false (два разных объекта)
🔍 Почему так?
Чтобы повысить производительность и сэкономить память, Java автоматически кеширует часто используемые значения.
🛠 Кстати, ты можешь изменить границу кеша через JVM-опцию:
-XX:AutoBoxCacheMax=512
📌 Полезно, если у тебя в системе часто используются числа вне стандартного диапазона.
#Java #Performance #JVM #DevTips
@javatg
Приглашаем Java-разработчиков на открытые занятия курса Java Микросервисы, Kafka, Docker, Spring Cloud, Spring WebFlux по всем основным темам микросервисной архитектуры.
🔥Курс фокусируется на применении всего технологического стека Spring Cloud (более 30-ти технологий) на реальном, "живом" проекте, с выполнением и разбором домашних заданий.
🔥Для участников есть персонализированная поддержка и живое общение в телеграм-группе с темами на каждое занятие. В том числе после завершения обучения.
ВЫ ПОЛУЧИТЕ:
⚡️ Полное понимание компонентов микросервисов и их взаимодействия
⚡️ Повышенная ценность, как Java-разработчика и новый уровень дохода
⚡️ Электронный сертификат об окончании курса
Ждем на нашем курсе!
https://www.tg-me.com/JavaOPsBot?start=c-cloud=s-javatg
🔥Курс фокусируется на применении всего технологического стека Spring Cloud (более 30-ти технологий) на реальном, "живом" проекте, с выполнением и разбором домашних заданий.
🔥Для участников есть персонализированная поддержка и живое общение в телеграм-группе с темами на каждое занятие. В том числе после завершения обучения.
ВЫ ПОЛУЧИТЕ:
⚡️ Полное понимание компонентов микросервисов и их взаимодействия
⚡️ Повышенная ценность, как Java-разработчика и новый уровень дохода
⚡️ Электронный сертификат об окончании курса
Ждем на нашем курсе!
https://www.tg-me.com/JavaOPsBot?start=c-cloud=s-javatg
💥 Задача: Почему эта структура «ломается» в многопоточной среде?
🔍 Разбор:
С первого взгляда кажется, что BrokenImmutable — иммутабельный класс. Мы оборачиваем Map через Collections.unmodifiableMap, и поле data — final.
Но проблема в глубине структуры.
unmodifiableMap запрещает перезапись ключей, но не делает элементы внутри truly immutable. В данном случае, значение по ключу "key" — это ArrayList, которую легко модифицировать.
💣 В main() мы получили доступ к внутреннему списку и… тихо сломали инвариант класса, добавив "🚨".
✅ Решение:
Чтобы сделать структуру действительно иммутабельной, нужно:
Копировать и оборачивать значения внутри Map.
Сделать глубокую защиту:
public BrokenImmutable(Map<String, List<String>> input) {
Map<String, List<String>> copy = new HashMap<>();
for (Map.Entry<String, List<String>> e : input.entrySet()) {
copy.put(e.getKey(), List.copyOf(e.getValue())); // immutable list
}
this.data = Map.copyOf(copy); // immutable map
}
Теперь никто не сможет мутировать data, даже если получит на него ссылку.
🧠 Вопрос на подумать:
А что если вместо ArrayList внутри Map был бы CopyOnWriteArrayList или ImmutableList от Guava? Почему CopyOnWriteArrayList — тоже плохой выбор для truly immutable структур?
@javatg
import java.util.*;
public class BrokenImmutable {
private final Map<String, List<String>> data;
public BrokenImmutable(Map<String, List<String>> input) {
this.data = Collections.unmodifiableMap(input);
}
public Map<String, List<String>> getData() {
return data;
}
public static void main(String[] args) {
Map<String, List<String>> base = new HashMap<>();
base.put("key", new ArrayList<>(List.of("a")));
BrokenImmutable bi = new BrokenImmutable(base);
Map<String, List<String>> d = bi.getData();
d.get("key").add("🚨");
System.out.println(bi.getData());
}
}
🔍 Разбор:
С первого взгляда кажется, что BrokenImmutable — иммутабельный класс. Мы оборачиваем Map через Collections.unmodifiableMap, и поле data — final.
Но проблема в глубине структуры.
unmodifiableMap запрещает перезапись ключей, но не делает элементы внутри truly immutable. В данном случае, значение по ключу "key" — это ArrayList, которую легко модифицировать.
💣 В main() мы получили доступ к внутреннему списку и… тихо сломали инвариант класса, добавив "🚨".
✅ Решение:
Копировать и оборачивать значения внутри Map.
Сделать глубокую защиту:
public BrokenImmutable(Map<String, List<String>> input) {
Map<String, List<String>> copy = new HashMap<>();
for (Map.Entry<String, List<String>> e : input.entrySet()) {
copy.put(e.getKey(), List.copyOf(e.getValue())); // immutable list
}
}
Теперь никто не сможет мутировать data, даже если получит на него ссылку.
🧠 Вопрос на подумать:
А что если вместо ArrayList внутри Map был бы CopyOnWriteArrayList или ImmutableList от Guava? Почему CopyOnWriteArrayList — тоже плохой выбор для truly immutable структур?
@javatg