Java
Самая актуальная информация по Java По всем вопросам- @haarrp @itchannels_telegram - 🔥лучшие каналы @pythonl - 🐍 @ai_machinelearning_big_data- ml @ArtificialIntelligencedl - AI @datascienceiot - ds @pythonlbooks 📚 РКН: clck.ru/3FmwKr #VRHSZ
Больше📈 Аналитический обзор Telegram-канала Java
Канал Java (@javatg) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 16 799 подписчиков, занимая 7 520 место в категории Технологии и приложения и 39 077 место в регионе Россия.
📊 Показатели аудитории и динамика
С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 16 799 подписчиков.
Согласно последним данным от 31 августа, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило -30, а за последние 24 часа — 17, при этом общий охват остаётся высоким.
- Статус верификации: Не верифицирован
- Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 11.16%. В первые 24 часа после публикации контент обычно набирает 5.30% реакций от общего числа подписчиков.
- Охват публикаций: В среднем каждый пост получает 1 874 просмотров. В течение первых суток публикация набирает 890 просмотров.
- Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 11.
- Тематические интересы: Контент сосредоточен на ключевых темах, таких как github, void, api, kotlin, static.
📝 Описание и контентная политика
Автор описывает ресурс как площадку для выражения субъективного мнения:
“Самая актуальная информация по Java
По всем вопросам- @haarrp
@itchannels_telegram - 🔥лучшие каналы
@pythonl - 🐍
@ai_machinelearning_big_data- ml
@ArtificialIntelligencedl - AI
@datascienceiot - ds
@pythonlbooks 📚
РКН: clck.ru/3FmwKr
#VR...”
Благодаря высокой частоте обновлений (последние данные получены 01 сентября, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.
Thread.sleep() - это просто пауза на заданное время.
Проблема в том, что ты угадываешь:
❌ поток может проснуться слишком рано
❌ или наоборот, ждать дольше, чем нужно
❌ polling через sleep() создаёт лишние задержки и проверки
Для координации потоков лучше использовать:
✅ wait() / notify()
✅ CountDownLatch
✅ другие примитивы синхронизации из java.util.concurrent
Например:
CountDownLatch done = new CountDownLatch(1);
done.await(); // ждём сигнал
done.countDown(); // работа завершена
А если задача должна выполняться периодически, вместо бесконечного цикла с sleep() лучше взять
ScheduledExecutorService exec =
Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(
this::doWork,
0,
1,
TimeUnit.SECONDS
);
Thread.sleep() хорошо подходит для простой задержки.
Для ожидания события и периодических задач в Java есть более точные инструменты.
#Java #Concurrencyspring-boot-mongodb
- работают напрямую с MongoDB driver
- для /actuator/health достаточно spring-boot-starter-mongodb
- Spring Data подключать не обязательно
То есть если сервис работает с MongoDB напрямую через драйвер, health check всё равно можно получить без лишней зависимости.
Полезное изменение для более лёгких Spring Boot 4 сервисов.. в формате числа не всегда означает точку
В DecimalFormat шаблон вроде:
#,###.##
не гарантирует вывод 1,234.56.
Символы зависят от locale:
🇺🇸 US → 1,234.56
🇮🇹 Italy → 1.234,56
Поэтому если формат предназначен для конкретной страны, лучше задавать её явно:
DecimalFormatSymbols it =
new DecimalFormatSymbols(Locale.ITALY);
DecimalFormat format =
new DecimalFormat("#,###.##", it);
Иначе приложение может внезапно начать форматировать числа иначе просто потому, что JVM запустили с другой локалью.
Мелочь, которая особенно неприятно всплывает в деньгах, отчётах и CSV.1.234,56 ломает Double.parseDouble()
В Java число - это не всегда просто строка с точкой.
Например:
Double.parseDouble("1.234,56");
закончится NumberFormatException.
Проблема в локали: в разных странах . и , означают разное.
Для таких случаев лучше использовать:
NumberFormat format =
NumberFormat.getInstance(Locale.ITALY);
Number value = format.parse("1.234,56");
double n = value.doubleValue();
Получим:
1234.56
Главное правило: если число пришло от пользователя, из CSV или внешней системы — сначала узнай его locale.
Иначе можно получить не только ошибку, но и тихо распарсить совсем не то число.@ConfigurationPropertiesSource позволяет генерировать metadata для типов, которые находятся не в текущем модуле, а, например, в общей библиотеке или отдельном starter-модуле.
Раньше с такими внешними типами IDE-подсказки для application.yml и application.properties могли быть неполными или вообще отсутствовать.
Теперь можно явно указать источник конфигурационных свойств и получить нормальную metadata даже для внешних классов.
Особенно полезно для:
— multi-module проектов
— внутренних Spring Boot starter'ов
— shared configuration libraries
— больших платформенных команд
Мелкая фича, но для DX в крупных Spring Boot проектах очень приятная.
#SpringBoot4 #Configrecord позволяет сильно сократить код.
Вместо обычного класса с полями, конструктором, equals(), hashCode() и toString() можно написать:
public record User(String name, int age, String email) {}
Java сама создаст:
user.name();
user.age();
user.email();
user.equals(other);
user.hashCode();
user.toString();
При этом record остаётся неизменяемым по ссылкам на свои компоненты: сеттеров нет, а поля фактически final.
Можно добавить и компактный конструктор для валидации:
public record User(String name, int age, String email) {
public User {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
}
}
Records появились как preview в Java 14 и стали полноценной частью языка в Java 16.
Удобный вариант для DTO, результатов запросов, событий, конфигурационных объектов и других небольших структур данных.clone() легко принять за полноценную копию объекта. Но super.clone() делает только shallow copy.
Сам объект будет новым, а ссылки на вложенные объекты останутся прежними.
То есть:
Main shallow = (Main) super.clone();
shallow и оригинал будут разными объектами, но dependency у них может указывать на один и тот же экземпляр.
Поэтому изменение вложенного объекта через одну копию неожиданно отразится и в другой.
Для deep copy нужно отдельно клонировать вложенные поля:
Main deep = (Main) super.clone();
deep.setDependency((Dependency) this.dependency.clone());
Теперь dependency тоже будет отдельным объектом.
Мелочь, на которой легко поймать очень неприятный баг: clone() копирует оболочку, а не весь граф объектов.JmsClient - более современная альтернатива привычному JmsTemplate.
Главное отличие - fluent API, из-за которого код отправки и получения сообщений становится заметно чище.
При этом JmsTemplate никуда не исчезает и продолжает работать без изменений.
Для старых проектов переписывать ничего не нужно, а для нового JMS-кода Spring теперь рекомендует смотреть в сторону JmsClient.
#SpringBoot4 #JMS
Map<List<Integer>, String> map = new HashMap<>();
List<Integer> key = new ArrayList<>(List.of(1, 2));
map.put(key, "Ritesh");
key.add(3);
System.out.println(map.get(key));
Многие ожидают:
Ritesh
Но результат:
```text
null
```
Почему?
HashMap ищет ключ через:
```java
hashCode()
equals()
```
Когда мы сделали:
```java
map.put(key, "Ritesh");
```
ключ был:
```text
[1, 2]
```
У него был один hashCode.
Но потом:
```java
key.add(3);
```
ключ стал:
```text
[1, 2, 3]
```
И его hashCode изменился.
HashMap уже положил объект в bucket по старому hash, а при get() ищет по новому.
Схема:
```text
put()
[1,2]
hash = X
↓
bucket X
key.add(3)
[1,2,3]
hash = Y
get()
ищем bucket Y
→ запись не найдена
```
Главное правило:
❌ Не изменяйте объект после того, как использовали его как ключ в HashMap.
Лучше использовать:
✅ String
✅ Integer
✅ record
✅ immutable-объекты
Например:
```java
Map<List<Integer>, String> map = new HashMap<>();
List<Integer> key = List.of(1, 2);
map.put(key, "value");
```
Самые опасные баги в Java - те, где объект всё ещё существует, ссылка всё та же, но структура данных уже не может его нормально найти.
#java #backend #programminginstanceof.
Старый вариант:
if (animal instanceof Dog) {
Dog d = (Dog) animal;
d.bark();
}
С pattern matching переменная объявляется прямо в проверке:
if (animal instanceof Dog d) {
d.bark();
}
d существует только там, где условие instanceof гарантированно истинно. Меньше кода, меньше лишних приведений типов и проще читать.
#Java #PatternMatchingTestRestTemplate на RestTestClient.
Почему это удобнее:
- fluent API в стиле RestClient;
- одинаковый подход для тестов через MockMvc и реальный HTTP-порт;
- проще читать цепочки request → response → assertions;
- меньше привязки к старому TestRestTemplate.
Пример:
restTestClient.get()
.uri("/api/users/42")
.exchange()
.expectStatus().isOk()
.expectBody(User.class)
.value(user -> assertThat(user.id()).isEqualTo(42));
Если автоконфигурация не подтянулась автоматически, добавляем:
@AutoConfigureRestTestClient
Если начинаете новый проект на Boot 4, TestRestTemplate уже вряд ли стоит выбирать по привычке.
#SpringBoot4 #Java #RestTestClient #Testing
private final AtomicLong requests = new AtomicLong();
requests.incrementAndGet();
Проблема: все потоки конкурируют за одну переменную.
Много потоков → больше CAS-коллизий → меньше производительность.
Для метрик лучше:
private final LongAdder requests = new LongAdder();
requests.increment();
Как работает:
AtomicLong:
Thread 1 ─┐
Thread 2 ─┼──> [100000]
Thread 3 ─┘
LongAdder:
Thread 1 → [10]
Thread 2 → [20]
Thread 3 → [15]
↓
sum()
LongAdder распределяет обновления между несколькими ячейками памяти, снижая конкуренцию.
Идеально для:
✅ Prometheus metrics
✅ счётчиков запросов
✅ статистики JVM
✅ rate limiter
Но важно:
adder.sum()
не гарантирует точный атомарный снимок.
Используйте:
- LongAdder → метрики и статистика;
- AtomicLong → когда нужно точное значение.
Одна замена класса может заметно улучшить производительность под нагрузкой.
#java #jvm #performancesynchronized и блокировки;
- проблемы с масштабированием.
Вместо того чтобы постоянно защищать изменяемое состояние, во многих случаях лучше проектировать код так, чтобы его было меньше изначально:
✅ immutable-объекты
✅ Java record
✅ concurrent-коллекции
✅ immutable snapshots через List.copyOf()
✅ минимум shared state
Например, ConcurrentLinkedQueue может убрать необходимость в грубой синхронизации для определённых сценариев, а record отлично подходит для неизменяемых доменных объектов.
Главная идея проста: чем меньше состояние можно изменить, тем меньше способов сломать многопоточный Java-код.
Но ConcurrentLinkedQueue не универсальная замена synchronized - выбор структуры данных всё равно должен исходить из требований к атомарности и консистентности.spring-boot-starter-undertow.
Если раньше было:
<artifactId>spring-boot-starter-undertow</artifactId>
теперь используйте Tomcat по умолчанию или подключайте Jetty:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Ещё один важный момент: не разворачивайте Spring Boot 4 в старом Servlet-контейнере — требуется совместимость с Servlet 6.1.
Перед миграцией Boot 3 → 4 обязательно проверьте серверную часть приложения.
#SpringBoot4 #Java #Servlet