ru
Feedback
Java: fill the gaps

Java: fill the gaps

Открыть в Telegram

Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк 🔥Тот самый курс по многопочке🔥 https://fillthegaps.ru/mt Комплименты, вопросы, предложения: @utki_letyat

Больше

📈 Аналитический обзор Telegram-канала Java: fill the gaps

Канал Java: fill the gaps (@java_fillthegaps) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 12 548 подписчиков, занимая 10 113 место в категории Технологии и приложения и 52 819 место в регионе Россия.

📊 Показатели аудитории и динамика

С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 12 548 подписчиков.

Согласно последним данным от 08 июня, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило -43, а за последние 24 часа — -3, при этом общий охват остаётся высоким.

  • Статус верификации: Не верифицирован
  • Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 34.73%. В первые 24 часа после публикации контент обычно набирает N/A% реакций от общего числа подписчиков.
  • Охват публикаций: В среднем каждый пост получает 0 просмотров. В течение первых суток публикация набирает 0 просмотров.
  • Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 0.
  • Тематические интересы: Контент сосредоточен на ключевых темах, таких как redis, hashmap, linkedhashmap, индекс, фича.

📝 Описание и контентная политика

Автор описывает ресурс как площадку для выражения субъективного мнения:
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк 🔥Тот самый курс по многопочке🔥 https://fillthegaps.ru/mt Комплименты, вопросы, предложения: @utki_letyat

Благодаря высокой частоте обновлений (последние данные получены 09 июня, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.

12 548
Подписчики
-324 часа
-207 дней
-4330 день
Архив постов
Тестирование, часть 1. Вопросы на собеседовании Чем опытней разработчик, тем больше тем обсуждается на собеседованиях. Начиная с уровня middle будьте готовы к таким вопросам: 1️⃣ Назовите свойства юнит-тестов? Хорошие юнит-тесты соблюдают принцип FIRST: 🔸F – Fast Выполняются быстро. Никто не хочет лишний раз запускать медленные тесты. Один юнит-тест — не дольше 0.5 сек. 🔸I – Isolated / Independent Любой набор тестов можно запускать в любом порядке, тесты не зависят друг на друга. Каждый тест сфокусирован на одном действии и наборе параметров. Если тест упал, то сразу понятно, где и при каких условиях возникла ошибка. 🔸R – Repeatable Результат теста не зависит от операционной системы, конфигурации компьютера, внешних ресурсов и наличия интернета. Результат теста повторяется при многократном вызове. ⭐️ Это свойство хромает, когда тесты используют случайные числа или проверяют работу нескольких потоков. 🔸S – Self-Validating У теста два результата — прошёл или нет. Разработчик не должен проверять записи в логе или сравнивать текстовые файлы. 🔸T - Timely Тесты пишутся вовремя, в рамках той же задачи, что и основной код. ⭐️ Юнит-тесты должны быть читаемыми. Тогда их легко поменять, если бизнес-логика изменится. Сложно разбираться в методах test1(), test2(), test3() и переменных a, b, c. ⭐️ По тестам можно оценить инженерную культуру компании. Обратите внимание на количество и качество юнит-тестов, кто и когда их пишет. Если тестов нет, или сеньор пишет код и создаёт подзадачу «написать тесты» для джуниора - это дно. Откладывать тесты из-за дедлайна — тоже так себе. ⭐️ Тесты можно не писать для PoC (proof of concept) — временный код для проверки гипотез, который не связан с продакшн кодом. Тесты организуют по структуре 3A (Arrange-Act-Assert), также встречается название Given-When-Then.
// given
Инициализация переменных и моков.
// when
Вызов проверяемого метода.
// then
Проверка результата и состояния других объектов. 3 блока должны чётко следовать друг за другом, тогда тест легко читать. Если после блока проверок идёт действие и дополнительные проверки — значит тест слишком большой. 2️⃣ Что такое TDD? Test Driven Development - процесс разработки, когда сначала пишется тест, а потом код. Подробно это выглядит так: ▫️Написать тест для кода, которого нет ▫️Запустить тесты, новый тест падает ▫️Написать код, чтобы тест проходил ▫️Запустить тесты, тесты проходят ▫️Рефакторинг нового кода ▫️Запустить тесты, тесты проходят Плюсы TDD: ➕Код сразу покрыт тестами ➕У класса удобный интерфейс, который сразу используется в тестах ➕Структурированный код После этого следует такой диалог: - А Вы лично используете TDD? - Нет. - Почему? У него же столько плюсов. - Большой минус - частое переключение контекста и фокус на деталях. Мне удобнее написать простое рабочее решение, и только потом добавить проверки, валидацию и обработку ошибок. После этого в соответствии с требованиями как следует оттестировать то, что получилось. Я сразу пишу код, который легко использовать и тестировать, поэтому TDD меня только замедляет. - Согласен.

Статический анализ кода, часть 2. Инструменты В части 1 обсудили основные метрики: связность, связанность, сложность и размер. Также статический анализ включает проверку форматирования, поиск уязвимостей и возможных ошибок. Когда и чем можно выполнять статистический анализ? 1️⃣ Во время написания кода. С помощью встроенных правил IDE и дополнительных плагинов: ▫️Checkstyle проверяет форматирование, возможные ошибки, показывает сложные классы. Самый популярный плагин для Intellij IDEA. ▫️SonarLint и FindBugs ищут возможные ошибки, уязвимости, проверяют код на несколько тысяч ошибочных паттернов. ▫️CodeMR замеряет атрибуты качества кода — связность, сложность и т.д. Считает метрики, рисует картинки, показывает проблемные места с точки зрения дизайна. ▫️PMD ищет ошибочные паттерны в разных категориях — дизайн, кодстайл, производительность. Не знаю, почему этот плагин попадает во все списки анализаторов, у него достаточно скудный список правил по сравнению с аналогами. 2️⃣ Во время сборки. Анализ редко делают в процессе сборки, но такая опция доступна — с помощью maven или gradle плагинов: Checkstyle Plugin, PMD Plugin. 3️⃣ На этапах CI/CD. Можно запускать периодически или после определённых событий: создание пул-реквеста, слияние ветки. Результаты могут иметь рекомендательный характер, а могут не пропускать дальше по CI. Конкретных инструментов много, как платных, так и бесплатных. Самый популярный - SonarQube. Метрики качества не считает, но проверяет на гигантское количество ошибочных паттернов и интегрируется с плагином в IDE. JArchitect менее распространён и стоит дороже. Но и функций больше — метрики качества и красивые графики. Статический анализ проводят в большинстве проектов. Обычно это проверка форматирования и поиск частых ошибок. Конкретные метрики считаются редко. И зря, ведь по ним можно объективно оценить: 🔸Текущее состояние кода 🔸Развитие системы от релиза к релизу 🔸Необходимость рефакторинга 🔸Проблемные места системы

Как на вашем проекте проверяется качество кода?
Anonymous voting

Статический анализ кода, часть 1. Основные метрики Главная цель принципов разработки и паттернов проектирования — снизить стоимость разработки. Хорошим считается код, который легко: 🔸читать 🔸менять 🔸тестировать 🔸переиспользовать Простота - субъективное понятие. Разработчику, который в проекте со дня основания, легко ориентироваться в коде и исправлять ошибки. Джуниор, который недавно пришёл и получил первое задание, вряд ли с ним согласится. К счастью, есть объективные показатели качества кода, которые можно отслеживать и анализировать. Их получают с помощью статического анализа на основе исходного и байт-кода. Базовых метрик больше 50, и обычно они группируются в 4 категории: 1️⃣ Связность (Cohesion) Показывает, насколько сильно внутренние элементы взаимодействуют друг с другом, насколько сфокусирован класс. В классе с низкой связностью много методов, которые мало взаимодействуют между собой:
class Программист {
   void написатьКод()
   void помытьПосуду()
   void погладитьКота()
}
Идеальная сущность с точки зрения Cohesion - лямбда-выражение. Их легко читать, тестировать и переиспользовать. 2️⃣ Связанность (Coupling) Показывает, как одна сущность взаимодействует с другими. Класс А связан с классом Б, если в классе А ▫️Поля класса Б ▫️Вызов методов класса Б ▫️Локальные переменные класса Б ▫️Если класс А - подкласс Б В большинстве проектов есть модуль base или common - часто он является примером сильной связанности. Менять такой модуль - всегда большой риск. 3️⃣ Сложность (Complexity) На этот показатель влияет: ▪️Сколько сущностей взаимодействуют ▪️Количество операций в методе ▪️Глубина наследования ▪️Количество ветвлений и возможных состояний Показатель сложности часто идёт рука об руку с размером, но не всегда. Сложный метод может быть небольшим по размеру, но скрывать внутри себя десятки вариантов развития событий:
public void check(long id) {
  dao.get(id).findProcessor()
  .getAccount().checkBalance();
}

4️⃣ Размер (Size) Большие сущности сложно поддерживать. В этой категории много метрик, например, количество: 🔹Полей 🔹Методов 🔹Статических методов 🔹Подклассов 🔹Связанных библиотек А теперь ответы на вопросы перед постом: ✅ Если класс А часто использует класс Б, то это признак высокой связанности. Связанность (coupling) характеризует внешние отношения между сущностями. Связность (cohesion) - про внутреннюю структуру самой сущности. ✅ На сложность влияет количество ветвлений и глубина наследования. Остальные характеристики относятся к категории "размер".

Что из этого напрямую влияет на показатель "сложность кода" (Complexity)?
Anonymous voting

Если внутри класса А часто используется класс Б, это
Anonymous voting

Intellij IDEA: комментарии TODO Часто встречаются ситуации, когда нужно запомнить место в коде: 🔸Внести изменения по задаче. 🔸Отметить непокрытый тестами код. 🔸Обсудить логику с коллегой. 🔸Сделать рефакторинг метода, не относящегося к задаче. Для таких случаев в IDEA есть специальный тип комментариев. Он начинается со слов TODO и выглядит так:
// TODO добавить тесты

Такие комментариии будут отображаться в окне TODO внизу экрана. Через него можно перейти в нужное место кода в один клик. Открыть список можно через ▫️Alt+6 ▫️View→Tool Windows→TODO Помимо стандартных TODO и FIXME можно добавить свои метки, например, OPTIMIZE, ASK, TEST. Сделать это можно в File →Settings→ Editor→ TODO.

Функциональные интерфейсы, часть 2. Best practices. В части 1 был обзор функциональных интерфейсов (ФИ), а в этом посте — 4 рекомендации по их использованию. 1️⃣ Не реализуйте ФИ через анонимные классы. Используйте лямбда-выражения и ссылки на методы. Это короче и понятнее. ✅ Runnable r=() -> … Runnable r=new Runnable{ @Override public void run(){…} } 2️⃣ Определите сценарии использования ФИ. ФИ — это интерфейс, но с одним абстрактным методом. В него можно добавить сколько угодно методов с реализацией — дефолтных, приватных и статических. Один ФИ может расширять другой ФИ. Класс может реализовать ФИ через implements. Чтобы код был простым и понятным, нужно разграничивать его компоненты: 🔸Цель обычного интерфейса - обозначить набор методов для будущих классов. 🔸Цель ФИ — передать набор инструкций через лямбды и ссылки на методы. Один метод в ФИ - оптимальный вариант. Но есть случаи, когда дополнительные методы уместны, так как тесно связаны с самим интерфейсом. Пример: интерфейс Predicate. Несмотря на то, что он функциональный, в нём есть 4 метода с заданной реализацией: and, or, isEqual и negate. 3️⃣ Используйте аннотацию FunctionalInterface. Она не обязательна, но облегчает чтение кода. 4️⃣ Если используете ФИ как аргумент, отражайте тип ФИ в названии метода. Пример: в классе 2 метода с одним именем и разными типами аргументов:
void adapt(Callable)
void adapt(Supplier)

Этот код компилируется, но у него 2 недостатка: ▪️Чтобы понять разницу между методами нужно читать код или документацию. ▪️В качестве аргумента нельзя передать лямбда-выражение, т.к оно подходит под оба типа:
❌ adapt(str->print(str))

Чтобы избежать этих проблем, используйте разные имена для методов. Хороший пример — класс CompletableFuture для многоэтапных вычислений. В его методах легко ориентироваться благодаря удачным названиям: ▫️thenAccept(Consumer) ▫️thenApply(Function) ▫️thenRun(Runnable)

Сколько методов может быть в функциональном интерфейсе?
Anonymous voting

Может ли класс реализовать функциональный интерфейс?
Anonymous voting

Функциональные интерфейсы, часть 1. Java 8 добавила много возможностей писать короткий и выразительный код. Одна из них — функциональный интерфейс (ФИ). Интерфейс считается функциональным, если у него только один абстрактный метод. Это единственное требование, даже аннотация FunctionalInterface необязательна. Например, у интерфейса Comparable всего один метод, по определению он функциональный, но аннотации у него нет. Во всём остальном ФИ - это обычный интерфейс. У метода можно объявлять исключения и использовать любые типы параметров:
@FunctionalInterface
public interface Archiver{
    void archive(String file) 
    throws FileNotFoundEx;
}

Экземплярами ФИ могут быть: 🔸Лямбда-выражение 🔸Ссылка на метод 🔸Ссылка на конструктор Для большинства задач подойдут стандартные интерфейсы из пакета java.util.function. Всего их 43, но можно выделить 5 групп: 1️⃣ Consumer (потребитель) Метод принимает один параметр и ничего не возвращает.
Consumer<String> c = 
   System.out::println;

2️⃣ Supplier (поставщик) Ничего не принимает, но возвращает значение.
Supplier<List> s = 
   ArrayList::new;

3️⃣ Function Принимает один параметр, возвращает одно значение:
Function<String,Long> map = 
   s -> Long.valueOf(s);

4️⃣ UnaryOperator Метод принимает один параметр и возвращает значение того же типа:
UnaryOperator<Integer> inc = 
   i -> i+1;

5️⃣ Predicate Принимает аргумент и возвращает boolean значение.
Predicate<String> filter = 
  s -> !s.isEmpty() 
    && !s.contains("q");

У этих ФИ есть удобные вариации: 🔹BiConsumer, BiFunction, BiPredicate, BinaryOperator принимают два аргумента:
BiConsumer<Integer,Integer> b = 
   (x,y) -> println(x+y);

🔹LongFunction, LongSupplier , ToLongFunction и т.д позволяют не прописывать типы аргументов или выходных значений:
LongFunction<String> to = 
   Long::toString;

Ответ на вопрос перед постом: Интерфейс становится функциональным если в нём есть один абстрактный метод. Все остальные свойства у него такие же, как у обычного интерфейса. Аннотация FunctionalInterface не обязательна, но желательна для понимания кода.

Есть ли у Вас в проекте свои функциональные интерфейсы?
Anonymous voting

Какие утверждения про функциональный интерфейс (ФИ) верны?
Anonymous voting

HeadHunter: 3 совета по поиску вакансий. 1️⃣ Не пользуйтесь фильтрами. Фильтрация скрывает вакансии, у которых параметры не выставлены или выставлены неверно: 🔸У 10% вакансий выставлен неподходящий опыт работы. Например, в Спб для Senior разработчиков есть 14 вакансий с тегом "опыт не требуется" или "1-3 года". 🔸Адрес стоит только у 53% вакансий. Иногда у компании есть несколько зданий в разных районах города, а указан адрес только одного из них. 🔸Уровень заработной платы указан в 17% вакансий. Это слабый ориентир, реальный диапазон зарплат часто шире указанного. Оффер зависит от опыта, соответствия проекту и наличию других кандидатов. 2️⃣ Пробуйте разные запросы в строке поиска. Границы Junior/Middle, Middle/Senior, Senior/Lead нечёткие, поэтому имеет смысл откликнуться на вакансии уровнем выше или ниже желаемой должности. Некоторые компании не акцентируют внимание на иерархии и называют все вакансии Java Developer. Технический специалист смотрит резюме и соотносит его с задачами проекта. Если Вы интересный кандидат, то без проблем получите подходящую должность и зарплату. Если Вы чётко уверены в своём уровне, пишите желаемую позицию на разных языках: Senior java / старший java Junior java / младший java 3️⃣ Исключите неподходящие варианты c помощью NOT. Это сокращает количество вариантов в 3-4 раза. Пример для бэкэнд java разработчика: java NOT QA NOT Android NOT Junior NOT Архитектор NOT DevOps

Технологии в вакансиях HeadHunter. Позиция: Java-разработчик Город: Санкт-Петербург Вакансий: 309 Собрала статистику вакансий HeadHunter для разработчиков с разным уровнем опыта. В списке указана технология и % упоминания в вакансиях. Это значит, что технология находится либо в требованиях, либо в описании проекта. Иногда категории объединены, а в скобках указаны самые распространенные варианты. Списки получились очень скучные, но хорошо отражают стек большинства java проектов🧐 Разработчики без опыта: 60▫️SQL (PostgreSQL, Oracle) 50▫️Spring (MVC, Boot, Security, Data) 45▫️Hibernate 40▫️Git 30▫️Maven 25▫️Apache Tomcat 25▫️Docker 20▫️Linux 15▫️Jenkins Опыт от года до 3х лет: 66🔸SQL 61🔸Spring (MVC, Boot, Security, Data, Cloud) 60🔸Git 34🔸Maven 34🔸Docker 30🔸Hibernate 21🔸Jenkins 17🔸Linux 17🔸Big Data (Hadoop) 17🔸Kotlin 11🔸Cloud платформы (AWS, GCP) Опыт от 3х до 6 лет: 69▪️SQL 67▪️Spring (MVC, Boot, Security, Data, Cloud) 40▪️Git 37▪️Docker 28▪️Maven 26▪️Hibernate 25▪️Apache Kafka 23▪️Kubernetes 21▪️Kotlin 18▪️jenkins 17▪️Linux 17▪️Cloud провайдеры 16▪️noSql (Redis, MongoDB, Cassandra, CouchBase) Опыт более 6 лет: 65🔹SQL 59🔹Spring (Boot, Data, Cloud) 35🔹noSql (Redis, MongoDB, Cassandra, CouchBase) 35🔹Big Data (Hadoop) 35🔹Docker 35🔹Cloud провайдеры (AWS, GCP) 29🔹Apache Kafka 24🔹Kotlin 24🔹Git 24🔹ElasticSearch 24🔹RabbitMQ 18🔹Maven 18🔹ELK 18🔹Kubernetes 12🔹SAP

Интерфейсы, часть 3: различия с абстрактным классом. Отличия интерфейса и абстрактного класса — популярный вопрос на собеседовании. Во времена java 7 ответ был простой: «В интерфейсе нет реализаций методов». В java 9 в интерфейс можно добавить приватные, статические и дефолтные методы с готовой реализацией. Это сближает интерфейсы с абстрактными классами. ❓В чём теперь разница интерфейса и абстрактного класса? Сравним по нескольким критериям: 1️⃣ Абстрактный класс. Можно добавить: ▪️Конструкторы. ▪️Реализацию экземплярных методов. ▪️Нестатические поля. ▪️private static поля. ▪️Модификаторы final, synchronized, protected. 🔨Использование: Класс реализует не больше одного абстрактного класса через ключевое слово extends. В имени часто содержится Abstract, Template, Base. ✴️ Назначение: Шаблон класса. Вспомогательная структура, чтобы не дублировать код в классах одной иерархии. ⭐️Репутация: Средняя. Абстрактный класс сокращает объем необходимого кода, когда иерархия классов конечна или известна заранее. Большое количество абстрактных классов считается анти-паттерном, у такой системы плохая читаемость, и в неё сложно вносить изменения. 2️⃣ Интерфейс ▪️Только статические поля. ▪️Методам с реализацией недоступны экземплярные поля, поэтому их возможности слабее, чем у абстрактных методов. 🔨Использование: Класс реализует несколько интерфейсов через ключевое слово implements. 5 лет назад интерфейсам было модно добавлять суффикс able: Iterable, Comparable. Норма сегодняшнего дня - называть интерфейс по тем же правилам, что и класс. ✴️ Назначение: Описывает методы для верхнеуровнего взаимодействия с классом, модулем или системой. ⭐️Репутация: Высокая. Широко используется в большинстве паттернов GoF, принципах SOLID. Поддерживает инкапсуляцию.

Что выведется в консоль?
Anonymous voting

Что выведется в консоль? Обратите внимание, интерфейс В теперь расширяет интерфейс А

Интерфейсы, часть 2: методы по умолчанию. В java 8 появилась новая возможность интерфейсов - методы с заданной реализацией:
interface Adapter {
   default int get() {…}
}
Класс, который реализует интерфейс, переопределяет такой метод при необходимости. ❓Зачем нужны такие методы? 1️⃣ Облегчить изменения API Во времена java 7 интерфейсы содержали только определения методов:
interface Collection<Т> {
   void add(Т);
   Т get();
}
Чтобы добавить, удалить или поменять сигнатуру метода нужно одновременно поменять код со стороны пользователей интерфейса и во всех реализациях. В рамках одного проекта это несложно, но для библиотек это сложная задача. Пользователи могут столкнутся с проблемами совместимости при переходе на новую версию. Задача дефолтных методов - сгладить этот процесс и предоставить приемлемую или временную альтернативу. 2️⃣ Вспомогательные методы Те методы, которые не входят в прямую функциональность интерфейса - методы для мониторинга, логгирования и т.д. Используйте с осторожностью, этот приём может нарушать принцип Interface segregation. 3️⃣ Комбинации базовых методов В интерфейсе объявляется минимально необходимый набор методов, а некоторые методы являются просто их комбинациями. Мы обсуждали этот случай в прошлом посте. Такой "удобный" метод можно добавить в интерфейс как статический. Статические методы вызываются через имя интерфейса и недоступны у экземпляров. Если это неудобно, оформите метод как метод по умолчанию. Пример: интерфейс Comparator. Основная функция — сравнение объектов через метод compare, индивидуальный для каждого класса. Цепочка из 2 компараторов - это 2 вызова compare и объединение результатов. Логика всегда одинакова, и нет смысла дублировать её в каждом подклассе:
default Comparator<T> thenComparing(Comparator) {…};

Что если класс реализует 2 интерфейса с методами по умолчанию? Для разрешения конфликта используются 2 правила: 1️⃣ Если в классе переопределён метод по умолчанию — используется метод класса. 2️⃣ В иерархии интерфейсов используется метод наследника:
interface Child extends Parent
Если класс реализует интерфейс Child, то будет использоваться дефолтный метод интерфейса Child. В опросе перед постом ни одно правило не подходит, поэтому будет ошибка компиляции. Чтобы разрешить конфликт, класс должен явно реализовать метод get();

Что выведется на консоль?
Anonymous voting