Java: fill the gaps
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк 🔥Тот самый курс по многопочке🔥 https://fillthegaps.ru/mt Комплименты, вопросы, предложения: @utki_letyat
Mostrar más📈 Análisis del canal de Telegram Java: fill the gaps
El canal Java: fill the gaps (@java_fillthegaps) en el segmento lingüístico de Ruso es un actor destacado. Actualmente la comunidad reúne a 12 549 suscriptores, ocupando la posición 10 120 en la categoría Tecnologías y Aplicaciones y el puesto 52 841 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 12 549 suscriptores.
Según los últimos datos del 07 junio, 2026, el canal mantiene una actividad estable. En los últimos 30 días la variación de miembros fue de -46, 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 34.72%. Durante las primeras 24 horas tras publicar, el contenido suele obtener N/A% de reacciones respecto al total de suscriptores.
- Alcance de las publicaciones: Cada publicación recibe en promedio 0 visualizaciones. En el primer día suele acumular 0 visualizaciones.
- Reacciones e interacción: La audiencia responde de forma activa: el promedio de reacciones por publicación es 0.
- Intereses temáticos: El contenido se centra en temas clave como redis, hashmap, linkedhashmap, индекс, фича.
📝 Descripción y política de contenido
El autor describe el recurso como un espacio para expresar opiniones subjetivas:
“Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк
🔥Тот самый курс по многопочке🔥
https://fillthegaps.ru/mt
Комплименты, вопросы, предложения: @utki_letyat”
Gracias a la alta frecuencia de actualizaciones (últimos datos recibidos el 08 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.
▫️ READ_UNCOMMITED ▫️ READ_COMMITED ▫️ REPEATABLE_READ ▫️ SERIALIZABLEКаждый уровень гарантирует решение чёткого списка проблем. Для остальных нужно либо писать код, либо забить на возможные неточности. В стандарте SQL описаны три проблемы: 🔸 Dirty reads - грязные чтения Транзакция 1 обновляет поле Х. Другие транзакции видят новое значения Х до того, как транзакция 1 завершится. В вопросе с переводом денег как раз возникла такая ситуация. Транзакция перевода ещё не завершилась, а другая транзакция прочитала промежуточные значения. Где возникает проблема: только на уровне READ_UNCOMMITED. 🔸 Nonrepeatable reads - неповторяющиеся чтения Транзакция 2 читает поле X и работает с ним. В это время транзакция 3 обновляет поле Х. В итоге транзакция 2 работает с устаревшим значением. Более формально, "неповторяющееся чтение" - когда чтение одного поля в начале и конце транзакции даёт разные результаты. Но редко кто читает одно поле дважды, на практике получается либо бесполезная транзакция с устаревшими данными, либо несогласованные данные внутри транзакции. Проблема остро проявляется для долгих запросов - бэкапов или аналитики. Решается на уровне REPEATABLE_READ и выше. 🔸 Фантомные чтения Транзакция 3 проверяет условие по большому количеству записей. Транзакция 4 меняет выборку, например, добавляет новую запись. Если условие в транзакции 3 перестанет выполнятся, транзакция 3 этого не заметит. Важно, что условие касается не одного поля, а многих. В этом разница с неповторяющимся чтением - там меняется одно конкретное поле, а в фантомном чтении меняется вся выборка, по которому проверяется условие. Проблема решается на уровне SERIALIZABLE. Подробные примеры и схемы аномалий есть в Википедии. Я перечислила основные, но у многих проблем есть разновидности, поэтому аномалий получается больше, чем уровней изоляции. Каждая БД сама решает, какие проблемы решать на конкретных уровнях. У MS SQL Server - 5 уровней, у Oracle - 3. Большинство NoSQL баз не поддерживают транзакции, поэтому для них указывать тип изоляции бессмысленно. В универсальных адаптерах типа JDBC, Hibernate и Spring Data уровней столько, сколько в стандарте - 4. Ещё одна проблема, которой нет в SQL стандарте, но встречается на практике: 🔸 Потерянный апдейт Транзакции работают с одними данными и не учитывают друг друга. Пример: транзакция 5 и транзакция 6 одновременно прочитали значение счётчика. Каждая транзакция прибавила к значению единицу и обновила поле счётчика. Вначале они прочитали одно значение, и получается, что один инкремент потерялся. Проблема решается не только уровнями изоляции, но и SQL конструкциями: 🔹 Атомарный апдейт:
UPDATE test SET x=x-1 where id=1;🔹 Блокировка строки:
SELECT * FROM test WHERE id = 1 FOR UPDATE;Итог. Как учитывать внутрянку БД в написании кода: 1️⃣ Выбирать уровень изоляции с учётом вероятности и критичности проблем 2️⃣ Уточнить в документации БД, какие проблемы решает выбранный уровень 3️⃣ Писать код с учётом возможных аномалий 4️⃣ Помнить о потерянных апдейтах
price numeric, sale_price numeric CHECK(price>sale_price)Условие "обычная цена выше скидочной" задано в пределах ОДНОЙ записи. БД контролирует это условие и выдаст ошибку при несоблюдении. 🔸 Другое дело - транзакция, в которой меняются РАЗНЫЕ записи. Нельзя атомарно перевести 100 рублей с одного аккаунта на другой. Будет момент, когда с одного аккаунта уже сняли 100 рублей, а на другой ещё не перевели. Целостность данных ненадолго нарушится. От уровня изоляции зависит, заметят ли несоответствие другие транзакции. Эту тему обсудим сегодня.
public native int hashCode();В разных JVM реализации могут отличаться. Рассмотрим исходный код hashcode() в OpenJDK. Там 6(!) стратегий вычисления хэшкода. Стратегия задаётся опциями VM:
-XX:+UnlockExperimentalVMOptions -XX:hashCode={число}
При первом вызове результат сохраняется внутри объекта. Хэшкод для Object считается один раз и не меняется, даже если объект перемещается в памяти. Посмотрим все возможные варианты:
🔸 Стратегия по умолчанию.
Случайное число по алгоритму Xorshift RNG. Следующее значение вычисляется на основе предыдущего. Значения равномерно распределены. У каждого потока свой генератор. Синхронизации между потоками нет, поэтому алгоритм работает быстро.
🔸-XX:hashCode=0
Случайное число по алгоритму Lehmer RNG. Генератор один на все потоки, поэтому работает медленно.
🔸-XX:hashCode=1
Адрес объекта в памяти и немного манипуляций с битами. Работает быстро, но не даёт равномерного распределения хэш кодов.
🔸-XX:hashCode=2
Чемпион по скорости, возвращает 1 для всех объектов:
java.lang.Object@1Используется как отправная точка для тестов остальных стратегий. 🔸
-XX:hashCode=3
Обычная возрастающая последовательность:
java.lang.Object@a4 java.lang.Object@a5 java.lang.Object@a6🔸
-XX:hashCode=4
Текущий адрес в памяти. Популярный, но неправильный ответ на собеседованиях. Отчасти в этом виновата документация: там адрес приводится как пример реализации.
Рейтинг стратегий по скорости:
🏆 Вернуть единицу: 184 операций за микросекунду
🥈 Вариант по умолчанию: 176 оп/мск
🥉 Адрес в памяти-1: 175 оп/мск
4️⃣ Адрес в памяти-2: 160 оп/мск
5️⃣ Растущая последовательность: 14 оп/мск
6️⃣ Случайное число и глобальная переменная: 10 оп/мск
Интересно, что до java 8 самая медленная опция была вариантом по умолчанию.
Резюме:
✅ Реализация хэшкода зависит от JVM и VM-флажков.
✅ Расчёт на основе адреса памяти не даёт равномерного распределения.
✅ Общие переменные в маленьких методах снижают производительность в 10 раз.
✅ В OpenJDK 6 стратегий вычисления хэшкода. По умолчанию используется генератор случайных чисел в рамках одного потока.toList()
С 25 по 27 ноября была серия постов о коллекторах (часть 1, часть 2, часть 3). Там я писала, что вместо
collect(Collectors.toList())было бы удобно писать просто
toList()30 ноября разработчик Oracle добавил метод toList() в класс Stream. Вряд ли он читает этот канал, но совпадение интересное🙂 Новый метод не совсем равнозначный: ▫️Collectors.toList() возвращает экземпляр ArrayList. ▫️Новый метод toList() возвращает неизменяемый список. 2️⃣ mapMulti Это оптизированный flatMap. Объясню суть на примере. Заказ - класс Order, товар - класс Item. Заказ состоит из нескольких товаров. Из списка заказов хотим получить список всех товаров.
orders.stream() .flatMap(order->order.getItems().stream()) .toList();flatMap переводит "список списков" в один список. Товары для каждого заказа превращаются в Stream, а метод flatMap объединяет эти стримы в один. Минус: объект стрима создаётся всегда, даже для пустых списков. mapMulti устраняет этот недостаток:
orders.stream() .<Item>mapMulti((order, consumer) -> order.getItems().forEach(item -> consumer.accept(item)) ).toList();Что происходит: mapMulti принимает на вход (order, consumer): ▪️order - элемент стрима, в нашем случае - заказ ▪️consumer - следующий этап в стриме. Наша задача - передать этому этапу все будущие элементы. Берём у заказа товары и для каждого вызываем consumer.accept(item). Мультимэп не знает, для каких объектов будет вызван accept, и не может вывести тип выходных элементов. Поэтому для нормальной работы тип надо указать явно:
<Item>mapMulti(…)Когда использовать mapMulti? ✅ Небольшое количество элементов в списках. Например, много заказов с 1-2 товарами ✅ Элементы легко получить без Stream API Основная фишка mapMulti - нет промежуточных стримов. Если внутри метода создаётся стрим, то вся выгода сходит на нет. ❌ order.getItems().stream()… Есть три вариации метода: 🔸IntStream mapMultiToInt 🔸LongStream mapMultiToLong 🔸DoubleStream mapMultiToDouble Для них выходной тип не указывается.
.class
Deprecated d = Account.class. getAnnotation(Deprecated.class)🔸 Делаем что-то полезное 🔸 Включаем процессор в компиляцию. В maven-compiler-plugin это секция annotationProcessors. Для обработки подойдут аннотации с любой RetentionPolicy. Что получаем: ❌ Долгая компиляция ❌ Специфичное тестирование. Пример 😐 Сложный и запутанный код ✅ Не тратится время на старте приложений Этот подход используется в библиотеке Lombok, микрофреймворках Quarkus и Micronaut, в Android фреймворке Dagger. Библиотека Dekorate на основе аннотаций создаёт манифесты для Kubernetes и OpenShift. 3️⃣ Статический анализ. Алгоритм такой же - создать наследник от AbstractProcessor, добавить в процесс компиляции. Примеры: библиотека Google Error Prone ищет в коде ошибки, Hibernate Validator проверяет, что аннотации Hibernate корректно расставлены. 4️⃣ Работа с байт-кодом. Редкий случай. В байт-коде остаются аннотации с RetentionPolicy.CLASS или RUNTIME. 5️⃣ Создать объекты и прокси-классы. Доступно для аннотаций с RetentionPolicy.RUNTIME. Основа работы многих фреймворков: Spring, Hibernate, Java EE. Под работу с аннотациями в рантайме заточены многие библиотеки: Reflections, Spring. Работать с ними удобно и приятно. Обработка рантайм-аннотаций обычно происходит на старте приложения, поэтому запуск сервиса может занимать несколько минут. ❌Теперь рассмотрим анти-кейсы, для чего аннотации НЕ нужны: 1️⃣ Отметить код для себя или команды. Поставить аннотацию @RefactorASAP легко, но без дальнейших действий это бесполезно. Аннотации нужно обрабатывать, и делать это автоматически. Чтобы запомнить место в коде, используйте TODO комментарии в Intellij IDEA. 2️⃣ Для бизнес-логики. Аннотации легко добавить в обход ООП и основной логики. Так можно быстро решить проблему, но долгосрочно это неудачный вариант: ❌ Нельзя контролировать процесс целиком ❌ Сложно писать тесты ❌ Сложно дебажить ❌ Внезапные сайд-эффекты Частая ситуация на Spring проектах: на старте запускаются десятки @PostConstruct. Если в процессе возникает ошибка, то найти и исправить её непросто. Но вообще, чем меньше вы полагаетесь на аннотации, тем лучше.
@Override, @Deprecated, @SuppressWarnings - вот это всё.
Первая часть будет о том, как сделать свою аннотацию, а во второй расскажу, когда и зачем это нужно.
Создать аннотацию легко:
public @interface MyAnnotation {}
❓Почему ключевое слово @интерфейс, а не @аннотейшн?
Во времена java 4 аннотаций не было и для дополнительной информации классу добавляли интерфейс-маркер. В интерфейсах Cloneable, Serializable, Remote нет методов, они используются только как дополнительный признак класса.
Подход рабочий, но похож на костыль. Цель интерфейса - показать контракт класса, поэтому для маркировки кода в java 5 ввели аннотации.
Вернёмся в наши дни. Посмотрим исходный код @Deprecated:
@Retention(RUNTIME)
@Target(value={FIELD,…})
public @interface Deprecated {
String since() default "";
boolean forRemoval() default false;
}
На этом примере видно, из чего состоит аннотация:
🔸Поля
Содержат доп. информацию. Если указать значение по умолчанию, поле становится необязательным:
@Deprecated(since="14")// forRemoval по умолчанию false 🔸Список внутри @Target показывает элементы, для которых работает аннотация. В java 7 аннотации доступны для классов, методов, параметров, полей и переменных. В java 8 аннотации действуют везде, где указан тип. Можно писать даже такое:
▫️new @Test Account() ▫️throws @Test IOException ▫️implements @Test Comparable<@Test
T>
Такие аннотации называются type annotations и используются в IDE и компиляторах для анализа и строгого контроля типов.
Аннотации нельзя ставить для имён переменных. Правильный ответ на вопрос перед постом - ошибка в 5 строке:
✅ @Test String doubled
❌ String @Test out
🔸@Retention определяет, когда доступна аннотация и как её можно использовать. Все виды подробно рассмотрим во второй части.
@Target и @Retention- это мета аннотации, то есть аннотации для аннотаций.
Какие ещё бывают мета-аннотации:
🔸@Documented - аннотация появится в JavaDoc
🔸@Inherited - наследуется подклассами
🔸@Repeatable (Java 8) - можно использовать несколько раз для одного элемента. Иногда такое приятнее читать, чем один массив:
@Schedule(dayOfMonth="last") @Schedule(dayOfWeek="Fri", hour="23")Создать аннотацию легко, правильно применить - уже сложнее. С этим вопросом разберёмся во второй части.
git push --force.
♊️ Близнецы
Год будет спокойным и приятным. В прошлом году вы много работали, в 2021 выделяйте больше времени на отдых. Качество жизни и работы только улучшится. Самое время взяться за большие и фундаментальные книги, которые вы долго откладывали.
♋️ Рак
Откажитесь от лишней эмоциональности, она может помешать вашему развитию. Подтяните DevOps, в этом году он вам пригодится. Сложные задачи ждут вас в середине лета, но они дадут нужный стимул для дальнейшего роста.
♌️ Лев
В этом году удача не на вашей стороне, придётся много работать. Хотите успеха — начните сейчас, чтобы уже весной видеть первые результаты. Смотрите на вещи шире. Почитайте книжки по архитектуре, посмотрите видео с конференций HighLoad и ArchDays. В апреле высокий риск простудиться, одевайтесь теплее.
♍️ Дева
Год будет богат на свежие идеи и начинания. Начните то, что давно откладывали. Интересные идеи, вопросы и решения придут в самый неожиданный момент. Сохраняйте их сразу - запишите в блокнот, голосовое сообщение, как угодно, а то улетят. Обязательно делайте бэкапы и резервные копии.
♎️ Весы
В этом году у Весов будет шанс попробовать себя в руководящей роли. Готовьтесь заранее - почитайте статьи по управлению людьми и проектами. Подтяните тайм-менеджмент, иначе времени на хобби и внерабочие активности совсем не останется.
♏️ Скорпион
В этом году вы будете на переднем фронте. Вас ждут горячие фиксы и спасение команды перед дедлайном. Будет сложно, но Сатурн вам поможет. Помните об отдыхе и набирайтесь сил в спокойное время.
♐️ Стрелец
Пересмотрите приоритеты в жизни, попробуйте смежные IT направления. Возможно позиция тимлида, менеджера или аналитика раскроют вас с новой стороны. В этом году особую важность приобретут межличностные отношения. Октябрь станет самым прибыльным месяцем в году.
♑️ Козерог
Для вас 2021 год — это борьба со своими слабостями. Уделяйте больше внимания тестированию и самопроверке. Разберитесь с NoSQL: книга для начинающих, для продолжающих. Хорошей идеей будет сходить на каток и покататься на ватрушках.
♒️ Водолей
Лучшее время для решительных шагов — начало весны. Много возможностей принесёт нетворкинг - поддерживайте тёплые отношения с коллегами, участвуйте в конференциях, митапах и корпоративных мероприятиях. Идите в ногу со временем - освойте Kotlin и Cloud computing.
♓️ Рыбы
Наступает период, когда пора применить все накопленные знания. А возможности для этого обязательно будут. Меркурий помешает сделать важные задачи в срок, поэтому закладывайте на выполнение в 2 раза больше времени. Лето подкинет массу интересных вариантов для отдыха.
Дружите со звёздами, они плохого не посоветуют💫switch (user.getState()) {
case NEW: …
case CONFIRMED: …
case BANNED: … }
Switch - это не просто набор нескольких if. У объекта user 3 статуса. Список чётко определен, статусы не пересекаются между собой.
Почему switch так себе вариант?
❌Сложный код. Работа со всеми состояниями в одной куче.
❌Дублирование кода. Если поле проверяется несколько раз, то менять такой код неудобно и легко ошибиться.
Для объекта с понятным набором состояний switch лучше заменить на полиморфные методы. Это несложный рефакторинг - пример1, пример2.
Цель ООП - смоделировать реальный мир через объекты. Главное здесь - объекты взаимодействуют и меняют состояние друг друга. В таких условиях switch проигрывает полиморфным методам и редко используется.
2️⃣ Часть 2. Эра функциональности
Сегодня для бизнеса недостаточно простой автоматизации. Основной задачей становится работа с данными.
Они не меняются, приходят из разных источников в разных форматах. Потоки данных идут через множество сервисов. Каждый сервис берёт данные, которые понимает, а остальные игнорирует. Строить иерархии классов для такой задачи кажется лишним и сложным.
Поэтому внедряются подходы из фунциональных языков. Один из них - pattern matching, а switch идеально подходит для его реализации. Паттерн - некоторое условие для переменной:
▫️Равна заданной константе
▫️Имеет определённый тип
▫️Подходит под регулярное выражение
Если произошёл мэтч, то для переменной сразу доступна доп.информация. Например, она приводится к нужному типу:
switch (animal) {
case Cat c → c.putToBox();
case Dog d → d.train(); }
Итак, в чём разница между switch в 2000 и switch в 2021?
Switch 2000 работает с объектами, у которых меняется состояние. Вокруг этого строится бизнес-логика.
Switch 2021 работает с неизменными данными и помогает найти среди них подходящие. В следующем году выйдет java 17, и switch будет появляться в коде чаще.
Вот так один непопулярный оператор в JDK нашёл своё место в мире спустя 23 года⭐️
¡Ya disponible! Investigación de Telegram 2025 — los principales insights del año 
