Java: fill the gaps
前往频道在 Telegram
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк 🔥Тот самый курс по многопочке🔥 https://fillthegaps.ru/mt Комплименты, вопросы, предложения: @utki_letyat
显示更多📈 Telegram 频道 Java: fill the gaps 的分析概览
频道 Java: fill the gaps (@java_fillthegaps) 俄语 语言赛道中的 是活跃参与者。目前社区聚集了 12 393 名订阅者,在 技术与应用 类别中位列第 9 836,并在 俄罗斯 地区排名第 52 005 位。
📊 受众指标与增长动态
自 невідомо 创建以来,项目保持高速增长,吸引了 12 393 名订阅者。
根据 28 八月, 2026 的最新数据,频道保持稳定运转。过去 30 天订阅人数变化为 -60,过去 24 小时变化为 -1,整体触达仍然可观。
- 认证状态: 未认证
- 互动率 (ER): 平均受众互动率为 0%。内容发布后 24 小时内通常能获得 N/A% 的反应,占订阅者总量。
- 帖子覆盖: 每篇帖子平均可获得 0 次浏览,首日通常累积 0 次浏览。
- 互动与反馈: 受众积极参与,单帖平均反应数为 0。
- 主题关注点: 内容集中在 redis, hashmap, linkedhashmap, индекс, фича 等核心主题上。
📝 描述与内容策略
作者将该频道定位为表达主观观点的平台:
“Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк
🔥Тот самый курс по многопочке🔥
https://fillthegaps.ru/mt
Комплименты, вопросы, предложения: @utki_letyat”
凭借高频更新(最新数据采集于 29 八月, 2026),频道始终保持新鲜度与高覆盖。分析显示受众积极互动,使其成为 技术与应用 类别中的关键影响点。
12 393
订阅者
-124 小时
-157 天
-6030 天
帖子存档
12 393
Интерфейсы. Часть 1: поля и методы.
Интерфейс — инструмент поддержки инкапсуляции. Что можно добавить в интерфейс в разных версиях java?
Java 7
Только нестатические public методы:
interface Интерфейс {
public void метод();
}
Классы реализуют эти методы под угрозой ошибки компиляции:
class M implements Интерфейс {
public void метод() {…};
}
Java 8
Появились 2 новых возможности:
1️⃣ Метод по умолчанию с заданной реализацией:
default void метод() {…};
Конкретный класс переопределяет его при необходимости.
❓Зачем они нужны?
Дефолтные методы уместны в трёх случаях, об этом будет статья в среду.
2️⃣ Статические методы с реализацией:
static void метод() {…};
Статические методы не наследуются и не переопределяются. Вызвать такой метод можно только через имя интерфейса:
Интерфейс.метод()❓Зачем они нужны? В интерфейсе определяется необходимый минимум методов. Например, в Collection это методы add(), remove() и другие. Чем меньше методов, тем больше свободы действий у конкретных классов. Эти базовые методы комбинируются между собой в другие полезные методы: ▪️Поиск элемента, ▪️Поиск минимального элемента, ▪️Скопировать коллекцию, Каждый из этих методов - всего лишь комбинация базовых, которая не зависит от конкретного класса. Чтобы не копировать код в каждый класс, сделайте такой метод статическим методом в интерфейсе:
static E min() {…};
До java 8 статические методы объединяли в утилитный класс с похожим именем. Например, методы binarySearch, copy, min реализованы в классе Collections.
Java 9
Можно добавить private и private static методы с реализацией:
private void m() {…};
private static void m() {…};
Эти методы недоступны для классов, реализующих интерфейс.
❓Зачем они нужны?
Чтобы выделить под-методы в дефолтных и статических методах, таким образом улучшить читаемость и избежать дублирования кода.
С методами разобрались, а какие поля можно добавлять в интерфейс?
Только константы с модификаторами public static. Из-за того, что других вариантов нет, в Intellij IDEA модификаторы public и static подсвечиваются как избыточные и вместо
public static int NUM = 1;допустима запись:
int NUM = 1;Такие поля компилируются в статические! Правильный ответ на вопрос: Ошибку компиляции в последней версии java вызовут варианты:
default int get(); private int get(); public static int get();У приватных, статических и дефолт методов в интерфейсах должна быть реализация.
12 393
Изучаете новую технологию? Не забывайте про контекст.
В интернете полно статей о языках программирования, фреймворках и библиотеках. Большинство из них показывают синтаксис на простых, но часто нереалистичных примерах. Этой информации хватает для собеседований, докладов и расширения кругозора. Однако для продуктивной работы важен не только синтаксис, но и контекст использования. Он включает в себя ответы на вопросы:
🔷Какую проблему решает Х?
🔷Какие альтернативы для решения этой же проблемы?
🔷В каких условиях Х лучше, чем альтернативы?
🔷За счёт чего Х лучше?
К сожалению, в статьях редко рассматриваются эти вопросы. Однако сценарии использования инструментов и альтернатив входят в понятие "опыт" разработчика и высоко ценятся на рынке.
Рассмотрим пример. Любой курс по многопоточности начинается с понятия потока и изучения класса Thread. Обычно автор описывает жизненный цикл потока, доступные методы и показывает пример создания потока с интерфейсами Runnable и Callable.
Можно ли на основе только этих знаний решать задачи? Можно, но вряд способ будет оптимальным. Посмотрим на класс Thread поближе и попробуем ответить на вопросы выше:
❓Какие задачи можно решать в отдельных потоках?
🔸Обработка большого количества данных
🔸Слабосвязанные подзадачи
❓Есть ли альтернативы для этих задач?
Обрабатывать данные можно с помощью ForkJoinPool. Для выполнения подзадачи в другом потоке есть ExecutorService. Можно использовать виртуальные потоки: Kotlin continuations, библиотеку Quasar и другие.
❓Когда ручное управление потоком лучше, чем варианты выше?
Сложно сказать. ForkJoinPool и ExecutorService эффективнее используют ресурсы и предоставляют высокоуровневый интерфейс, поэтому ими легко пользоваться. Виртуальные потоки лучше работают с маленькими задачами и блокирующими вызовами.
Класс Thread появился в java 1.2. Это низкоуровневый инструмент, в 2020 году с ним решаются только очень специфичные задачи. Для популярных задач появилось много специализированных классов и фреймворков.
Обзорные статьи и доклады - это стартовые точки при изучении технологий. Нужно двигаться к пониманию, как и когда это применять на практике. Как это сделать? Лёгкого пути нет, нужно по крупицам собирать общую картину из разных источников и, конечно, читать посты на @java_fillthegaps💪
12 393
Java 8-11: новые методы String.
Чтобы не писать велосипеды и не добавлять в проект лишние библиотеки, посмотрите на новые методы в классе String:
🔸Соединить строки через разделитель:
String.join("-","1","2");
// 1-2
Можно использовать со списком строк:
List<String> list = ...;
String.join("-", list);
🔸Убрать пробелы и служебные символы
▪️с начала строки:
str.stripLeading();
▪️в конце строки:
str.stripTrailing();
▪️с обеих сторон:
str.strip();
В классе уже присутствует метод trim(), который тоже стирает неподходящие символы. strip() корректнее определяет недопустимые символы, в том числе экзотические виды пробелов ('\u00A0', '\u2007', '\u202F').
🔸Проверить, что строка пуста:
str.isBlank()На замену StringUtils.isBlank() из библиотеки Apache Commons. 🔸Создать стрим из строки. Можно разделить текст ▪️по линиям:
str.lines()
▪️по символам: str.chars()
🔸Продублировать строку:
"<td>".repeat(3);
// <td><td><td>12 393
Система типов и проверка аргументов.
Язык программирования строится на многих формальных теориях. Одна из них - система типов. От неё зависит реализация языка, скорость компиляции и работы программы. Тема этого поста: как проверяются аргументы метода. Кажется, что ничего сложного здесь нет, но каждый язык делает это по-своему.
Первый вопрос: когда происходит проверка? В зависимости от ответа типизация может быть:
🔸Cтатической
🔸Динамической
При статической тип указателя навсегда закрепляется при создании:
String str;Ассоциированный объект имеет тот же тип или производный. Т.к типы известны заранее, проверка аргументов происходит во время компиляции. ✅ Отлавливается много ошибок. ✅ Быстро работает в рантайме. ✅ Предсказуемое поведение. ✅ Легко тестировать. При динамической типизации указатель не имеет типа. Во время работы программы в переменную можно записать любые значения:
value = "а" value = 4Аргументы проверяются во время вызова метода. Такие программы в разы короче и легко адаптируются к изменениям. Java является языком со статической типизацией. Второй вопрос, на который отвечает система типов: что делать, если метод принимает тип А, но приходит объект типа Б? Можно: ▪️Бросить ошибку. ▪️Преобразовать Б в тип А. У языка сильная типизация, если допустимо мало преобразований. Если много, то типизация слабая. Речь идёт о неявных преобразованиях, которые делает компилятор или исполняющая среда. Пример:
5L + 1
Язык Ruby не разрешает складывать числа разных типов, а java приведёт единицу к типу long и выполнит сложение. Выражение
5 + trueв java вызовет ошибку компиляции. JavaScript спокойно переведёт true в единицу. Компилятор java может перевести: - подкласс в суперкласс - long в int и наоборот - int в Integer и наоборот и так далее. Некоторые правила работают в одних условиях, некоторые в других. В целом java считается языком с сильной типизацией. Вернёмся к вопросу перед постом. Метод
id ожидает аргумент типа Long, а передаётся примитивный int. В правилах преобразований нет перехода int → Long, поэтому будет ошибка компиляции. Достичь цели можно в 2 шага:
int → long
long → Long
Компилятор может выполнить только один шаг, второе преобразование делает программист. Поэтому подходящий ответ:
(long) intValue12 393
IntelliJ IDEA: быстрый поиск.
Двойное нажатие Shift - универсальный шорткат для поиска. Он поможет:
✅ Найти класс, метод или файл.
✅ Открыть настройки: Tab Size, Code style, ...
✅ Выполнить команду:
Optimize imports,
Push (в репозиторий),
Show history,
Rename,
Presentation Mode
...и многие другие. Просто нажмите Shift-Shift, начните набирать слово и выберите подходящий вариант из списка.
12 393
Stream API: ускоряемся🚀
Stream API помогает писать выразительный код, который быстро работает. Несложными действиями можно повысить скорость ещё больше:
1️⃣ Добавить parallel().
Для поддержки параллельности нужны дополнительные ресурсы, и прирост скорости заметен только если в коллекции много элементов. Если:
N – количество элементов,
Q – количество операций над каждым элементом,
то при N*Q>10000 можно смело добавлять parallel()
2️⃣ Добавить или удалить sorted(), unordered().
🔸sorted(): отсортировать стрим и добавить свойство «отсортирован».
🔸unordered(): выставить свойство «порядок не важен».
Источник данных и методы sorted, unordered, dictinct,... определяют свойства стрима: конечный размер, уникальность, отсортированные значения и другие. Благодаря этому некоторые методы оптимизируют работу. Если порядок не важен, параллельная обработка будет быстрее. Если список уже отсортирован, удаление повторяющихся элементов distinct() займёт меньше времени. Иногда наоборот — дополнительные ограничения замедляют работу.
Другие специфичные примеры.
3️⃣ Пользоваться специальными методами.
Чем меньше операций, тем быстрее всё работает. Проверить, что ни один элемент не удовлетворяет условию можно так:
filter(...).findFirst().isPresent()
а можно короче, понятнее и быстрее:
noneMatch(...)
Иногда стримы даже не нужны, много полезных методов есть в интерфейсе Collections. Например, максимальный элемент в списке быстрее найти через Collections.max(...), чем с использованием стрима.
Больше примеров
4️⃣ Объединить однотипные операции.
Чаще это касается сложной фильтрации:
filter(1).filter(2).filter(3)
можно ускорить в 2-4 раза, если объединить условия:
filter(1 & 2 & 3)12 393
Что вернётся из try-catch-finally?
Вопросы такого типа популярны на собеседованиях. Поведение
try-catch-finally в спецификации описывается через 24 предложения "если". Логика запутанная, и легко допустить ошибку.
Чтобы решать такие задачки, воспользуйтесь следующей моделью:
Результатом блока try-catch-finally могут быть 3 варианта:
🔸Ничего
🔸Возврат значения
🔸Исключение
Представим, что результат записывается в переменную result. В начале работы там "ничего".
Блоки обрабатываются в строгом порядке:
1️⃣ try
2️⃣ catch
3️⃣ finally
На каждом шаге переменная result может быть перезаписана. Итоговое значение result и будет результатом выполнения. Особый случай — при вызове System.exit(0) выполнение прекращается сразу же .
Разберём пример из опроса:
▫️try установит результат на "вернуть try".
▫️Блока catch нет.
▫️В finally результат меняется на "вернуть finally".
Итог: вернётся "finally"
Другой пример:
try { throw new NPE(); }
catch (SecurityEx e)
{ return "ex"; }
finally {}
▫️В блоке try результатом станет "NPE".
▫️Блок catch пропускается, т.к нет подходящего типа исключения.
▫️В блоке finally результат не переопределяется.
Итог: выброс NPE.
Этот пример важен, потому что такие ошибки часто встречаются на практике. Блок finally - не оберег от исключений. Если результат "исключение" дальше не переопределён, он пробрасывается в вышестоящий метод.12 393
Best practices: как проверять входные данные.
Запросы пользователей и ответы сторонних систем иногда приходят некорретными или в неправильном формате. Проверить данные можно по-разному, посмотрим разные варианты на простом примере:
String info(Request req) {
return req.toString(); }
Для нормальной работы параметр req не должен быть пустым. Мы можем:
1️⃣ Оставить как есть: тогда JVM выбросит NullPointerException(NPE)
2️⃣ Добавить проверку и самим бросить исключение:
if (req==null) throw new NPE();3️⃣ Добавить проверку и вернуть null:
if (req==null) return null;4️⃣ Добавить проверку и вернуть Optional.empty():
if (req==null) return Optional.empty();Оценим их с точки зрения производительности и дизайна. Начнём с производительности. Запустим каждый вариант миллион раз: ▪️14 мс - JVM исключение ▪️2 мс - явный выброс исключения ▪️0,03 мс - null ▪️0,03 мс - Optional.empty() Что это значит? 1️⃣ Создание исключения гораздо дольше, чем выход из метода. Время уходит на создание стек-трейса - чем он глубже, тем хуже производительность. Стек-трейс из сервиса на Spring Boot собирается в 50-100 раз дольше, чем стек-трейс из метода main. 2️⃣ Если исключение явно создаётся в коде, JVM переиспользует ранее собранный стэк-трейс. Так получается выигрыш в 5-10 раз, но разница с вариантом без исключения всё ещё внушительна. По этим цифрам легко решить, что исключения - удар по производительности. 10 лет назад была тенденция избегать исключений любой ценой. Например, возвращать из метода пару (результат, код_ошибки). В 2020 это уже не актуально. Если взаимодействие в системе не построено на исключениях, то это капля в море относительно других операций. В примере сверху исключение создаётся миллион раз подряд - такого в продакшене обычно нет. Исключения делают код чище: 🔹Понятное возвращаемое значение 🔹В части throws явно обозначены непредвиденные ситуации 🔹Логика метода и обработка ошибок разделены Теперь сравним создание исключения и возврат null с точки зрения дизайна. Исключение подразумевает обработку ошибки, например: 🔸Показать пользователю сообщение. 🔸Прекратить работу с файлом. 🔸Поменять формат данных. Optional.empty(), null или объект по умолчанию возвращается, когда реагировать на ситуацию необязательно. Например, когда данные быстро устаревают. Возвращаемый тип Optional удобнее использовать: не нужно смотреть в документации, возвращает ли функция пустой результат, и как он обозначается: null, -1 или 0.
12 393
Какой метод вызвать у экземпляра?
В java этот вопрос решается двумя способами:
🔸Раннее связывание
🔸Позднее связывание
Раннее связывание включается при вызове методов с модификаторами
static, private, final. Метод определяется по типу ссылки во время компиляции, и его нельзя переопределить. Благодаря раннему связыванию JVM не тратит ресурсы во время работы программы, поэтому скорость вызова этих методов чуть выше.
Позднее связывание работает для остальных public и protected методов. JVM в рантайме определяет тип объекта и метод, который нужно вызвать. Этот механизм лежит в основе полиморфизма, наследования и инкапсуляции.
Статические методы в классах Parent и Child не переопределяют друг друга и относятся к разным классам. Над методом в классе Child нельзя даже поставить @Override и вызвать внутри super.getName();
Поэтому правильный ответ в опросе выше — "Parent", потому что метод определён во время компиляции по типу указателя.
Если посмотреть на вызов метода у объекта, то непонятно, статический он или обычный, учитывается тип экземпляра или нет. Это приводит к ошибкам и считается плохой практикой. Настолько плохой, что для объекта Intellij IDEA даже не показывает статические методы в выпадающем списке. Хороший вариант — вызывать статические методы, обращаясь к классу:
println(Parent.getName());На собеседованиях встречается модификация этого вопроса — один метод
getName() статический, а другой — нет. В этом случае будет ошибка компиляции, потому что непонятно, какой механизм связывания использовать.