ar
Feedback
Java: fill the gaps

Java: fill the gaps

الذهاب إلى القناة على Telegram

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

إظهار المزيد

📈 نظرة تحليلية على قناة تيليجرام 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

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