ch
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: поля и методы. Интерфейс — инструмент поддержки инкапсуляции. Что можно добавить в интерфейс в разных версиях 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();

У приватных, статических и дефолт методов в интерфейсах должна быть реализация.

public interface Adapter {
Anonymous voting

Что из нижеперечисленного вызовет ошибку компиляции?

Изучаете новую технологию? Не забывайте про контекст. В интернете полно статей о языках программирования, фреймворках и библиотеках. Большинство из них показывают синтаксис на простых, но часто нереалистичных примерах. Этой информации хватает для собеседований, докладов и расширения кругозора. Однако для продуктивной работы важен не только синтаксис, но и контекст использования. Он включает в себя ответы на вопросы: 🔷Какую проблему решает Х? 🔷Какие альтернативы для решения этой же проблемы? 🔷В каких условиях Х лучше, чем альтернативы? 🔷За счёт чего Х лучше? К сожалению, в статьях редко рассматриваются эти вопросы. Однако сценарии использования инструментов и альтернатив входят в понятие "опыт" разработчика и высоко ценятся на рынке. Рассмотрим пример. Любой курс по многопоточности начинается с понятия потока и изучения класса Thread. Обычно автор описывает жизненный цикл потока, доступные методы и показывает пример создания потока с интерфейсами Runnable и Callable. Можно ли на основе только этих знаний решать задачи? Можно, но вряд способ будет оптимальным. Посмотрим на класс Thread поближе и попробуем ответить на вопросы выше: ❓Какие задачи можно решать в отдельных потоках? 🔸Обработка большого количества данных 🔸Слабосвязанные подзадачи ❓Есть ли альтернативы для этих задач? Обрабатывать данные можно с помощью ForkJoinPool. Для выполнения подзадачи в другом потоке есть ExecutorService. Можно использовать виртуальные потоки: Kotlin continuations, библиотеку Quasar и другие. ❓Когда ручное управление потоком лучше, чем варианты выше? Сложно сказать. ForkJoinPool и ExecutorService эффективнее используют ресурсы и предоставляют высокоуровневый интерфейс, поэтому ими легко пользоваться. Виртуальные потоки лучше работают с маленькими задачами и блокирующими вызовами. Класс Thread появился в java 1.2. Это низкоуровневый инструмент, в 2020 году с ним решаются только очень специфичные задачи. Для популярных задач появилось много специализированных классов и фреймворков. Обзорные статьи и доклады - это стартовые точки при изучении технологий. Нужно двигаться к пониманию, как и когда это применять на практике. Как это сделать? Лёгкого пути нет, нужно по крупицам собирать общую картину из разных источников и, конечно, читать посты на @java_fillthegaps💪

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>

Система типов и проверка аргументов. Язык программирования строится на многих формальных теориях. Одна из них - система типов. От неё зависит реализация языка, скорость компиляции и работы программы. Тема этого поста: как проверяются аргументы метода. Кажется, что ничего сложного здесь нет, но каждый язык делает это по-своему. Первый вопрос: когда происходит проверка? В зависимости от ответа типизация может быть: 🔸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) intValue

Скомпилируется ли код выше?
Anonymous voting

Скомпилируется ли этот код?

IntelliJ IDEA: быстрый поиск. Двойное нажатие Shift - универсальный шорткат для поиска. Он поможет: ✅ Найти класс, метод или файл. ✅ Открыть настройки: Tab Size, Code style, ... ✅ Выполнить команду: Optimize imports, Push (в репозиторий), Show history, Rename, Presentation Mode ...и многие другие. Просто нажмите Shift-Shift, начните набирать слово и выберите подходящий вариант из списка.

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)

Что вернёт метод?
Anonymous voting

Что вернёт метод?

Что вернётся из 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 - не оберег от исключений. Если результат "исключение" дальше не переопределён, он пробрасывается в вышестоящий метод.

Что вернёт метод?
Anonymous voting

Что вернёт метод?

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.

Какой метод вызвать у экземпляра? В java этот вопрос решается двумя способами: 🔸Раннее связывание 🔸Позднее связывание Раннее связывание включается при вызове методов с модификаторами static, private, final. Метод определяется по типу ссылки во время компиляции, и его нельзя переопределить. Благодаря раннему связыванию JVM не тратит ресурсы во время работы программы, поэтому скорость вызова этих методов чуть выше. Позднее связывание работает для остальных public и protected методов. JVM в рантайме определяет тип объекта и метод, который нужно вызвать. Этот механизм лежит в основе полиморфизма, наследования и инкапсуляции. Статические методы в классах Parent и Child не переопределяют друг друга и относятся к разным классам. Над методом в классе Child нельзя даже поставить @Override и вызвать внутри super.getName(); Поэтому правильный ответ в опросе выше — "Parent", потому что метод определён во время компиляции по типу указателя. Если посмотреть на вызов метода у объекта, то непонятно, статический он или обычный, учитывается тип экземпляра или нет. Это приводит к ошибкам и считается плохой практикой. Настолько плохой, что для объекта Intellij IDEA даже не показывает статические методы в выпадающем списке. Хороший вариант — вызывать статические методы, обращаясь к классу:
println(Parent.getName());

На собеседованиях встречается модификация этого вопроса — один метод getName() статический, а другой — нет. В этом случае будет ошибка компиляции, потому что непонятно, какой механизм связывания использовать.

В консоли будет напечатано:
Anonymous voting

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