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 549 подписчиков, занимая 10 121 место в категории Технологии и приложения и 52 862 место в регионе Россия.

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

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

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

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

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

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

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

12 549
Подписчики
Нет данных24 часа
-247 дней
-4630 день
Архив постов
Что такое идемпотентность?
Anonymous voting

Небольшой апдейт: в scala список односвязный Спасибо неравнодушным подписчикам!

Списки, часть 2: что и когда использовать В большинстве статей пишут, что LinkedList подходит для частой вставки или удаления элементов. На JavaRush также упоминают обход списка с периодической вставкой. В теории всё так, но обычно в энтерпрайзе менее изысканные задачи: 🔸 Заполнить список 🔸 Отсортировать (встроенной функцией, конечно) 🔸 Обойти все элементы 🔸 Сделать что-нибудь с помощью Stream API Для этих сценариев я сделала бенчмарки. У Stream API выделила 4 случая: ▫️ Простой однопоточный: stream→filter→collect ▫️ Сложный однопоточный: stream→map→filter→map→filter→collect ▫️ Простой с опцией parallel() ▫️ Сложный с опцией parallel() Начнём с заполнения списка. В прошлом посте выяснили, что до 100к элементов между списками почти нет разницы. ArrayList тратит много времени на копирование, а LinkedList — на создание обёрток и соединение ссылок. Если количество элементов известно заранее, его можно указать в конструкторе:
List list = new ArrayList(25);

Без лишнего копирования и переносов разница в скорости становится ошеломительной — список заполняется на 20-80% быстрее! Также ArrayList однозначно победил в номинациях: 🔹 Сортировка 🔹 Обход через цикл for 🔹 Простые Stream API 🔹 Любые Stream API с опцией parallel() В сложных однопоточных Stream API большая часть вычислений идёт на что-то полезное, и влияние оверхеда снижается. Ожидаемо:) Ещё факты против LinkedList: 🔸 Большинство классов JDK используют ArrayList для внутренних задач 🔸 Joshua Bloch (автор класса и книжки Effective Java) в 2015 написал твит:
"Does anyone actually use LinkedList? I wrote it, and I never use it."

Но аналоги LinkedList иногда встречаются. В Scala для неизменяемого списка за основу взят именно двусвязный. Возможно, это лучше для каких-то сценариев, но пока не знаю для каких. На картинке часть моих бенчмарков. N — количество элементов в списке. Зелёный цвет обозначает победителя в категории. Ярко-зелёный — разница значений более 50%. ❗️Результаты на разных железках могут отличаться ❗️

Списки, часть 1: строение и основные операции 1. Внутреннее устройство В сердце ArrayList лежит массив:
Object[] elementData;

Размер массива задаётся в конструкторе: new ArrayList(50). Значение по умолчанию — пустой массив. Структура LinkedList чуть сложнее. Каждый элемент оборачивается в класс:
private static class Node {
   E item;
   Node next;
   Node prev;
}

Т.е сам элемент списка + указатели на следующий и предыдущий элемент. В объекте LinkedList хранится ссылка на первый и последний элемент списка:
Node first;
Node last;

2. Доступ по индексу: list.get(i) или list.set(i) ArrayList просто обращается по индексу массива LinkedList идёт долгим путём. Берёт элемент first идёт по ссылкам, пока не дойдёт до i-го элемента. Затем либо возвращает значение, либо обновляет. Кажется, что второй подход гораздо дольше. И это правда🙂 Чтобы получить 5000-ый элемент в списке из 10к элементов ArrayList тратит 6 наносекунд, а LinkedList — 8750. Чем больше элементов, тем больше разница. 3. Вставка в середину списка ArrayList Допустим, для списка 🟧🟧🟧🟧 вызвали метод add(2, 🦄) Создаётся новый массив размером +1: ⬜️⬜️⬜️⬜️⬜️ Все элементы старого списка копируются туда так, чтобы образовалось свободное место для нового элемента: 🟧🟧⬜️🟧🟧 Обновляем элемент: 🟧🟧🦄🟧🟧 LinkedList Рассмотрим тот же метод add(2, 🦄): ▫️ Создаём элемент списка с двумя ссылками: ⬅️🦄➡️ ▫️ Идём до текущего элемента 2 и получаем ссылки на элементы 1 и 3 ▫️ У элемента 1 обновляем ссылку на next, у 3 — на prev Само добавление простое, но перед ним нужно пройтись по списку. Это долго, поэтому LinkedList и здесь проигрывает по скорости. 4. Заполнение списка (см код в вопросе перед постом) ArrayList ▫️ Создаётся пустой массив ▫️ При первом add размер увеличивается до 10 ▫️ При добавлении 11 элемента создаётся новый массив размером 15. Предыдущие элементы копируются, затем добавляется новый ▫️ И так далее: когда места не хватает, создаётся массив в 1.5 раза больше LinkedList У текущего tail элемента обновляется ссылка next. Новый объект записывается как tail. Что работает быстрее? Интуиция подсказывает, что LinkedList, так как для ArrayList нужно часто переносить элементы в новый массив. На самом деле операции копирования выполняются быстро, так как элементы лежат в памяти рядом, а у процессоров хорошая поддержка этой операции. Бенчмарки показывают, что до 100к элементов разницы нет, а потом побеждает ArrayList. А при миллионе элементов ArrayList копируется реже и в итоге заполняется в два раза быстрее. Внизу таблица JMH бенчмарков с моего компьютера. На других железках результаты могут отличаться. Ответ на вопрос перед постом: для 50к элементов время почти одинаковое.

Какой список в коде выше заполняется быстрее?
Anonymous voting

Какой список в коде ниже заполняется быстрее?

Списки — простая структура данных и популярная тема на собеседованиях. Просят рассказать про строение, оценить сложность операций и случаи использования. Отвечаешь, что в ArrayList быстрый доступ по индексу, а в LinkedList легко вставлять элементы в середину списка. Получаешь оффер🙂 Но это немного скучно, поэтому решила описать более жизненные кейсы и подробнее написать про строение. И самое главное — измерить время работы операций! 🔸 Часть 1: вводная. Строение списков и основные операции 🔸 Часть 2: жизненная. Что и когда использовать в коде

Сбой в работе Wildberries Сегодня необычный пост — расскажу вам новости и слухи🙂 С 14 марта в работе Wildberries наблюдались сбои — главная страница открывается, но пропали данные о прошлых заказах, новые заказы не оформляются, а в личном кабинете не отображается имя пользователя. Компания пишет о технических сбоях, но в интернете ходят слухи, что это хакерская атака. Известных деталей мало, а я не спец в кибербезопасности. Пишу свои предположения на основе слухов и похожих случаев. На самом деле может быть по-другому. Вероятный ход событий: 1️⃣ Сотрудник в Wildberries получил письмо со ссылкой, щёлкнул по ней и скачал дроппер. Дроппер — программа, которая устанавливает другое вредоносное ПО и по возможности нейтрализует защиту ОС. В Windows дропперы часто выключают службу, которая предупреждает о попытках внести изменения в систему. Письмо выглядит правдоподобно — красивая разметка, официальный стиль, актуальные новости. Это самое популярное начало атаки: 🔸 В начале пандемии COVID-19 компаниям приходили "рекомендации" по безопасной работе 🔸 Руководителю одного банка пришло письмо “журналистки РБК” с просьбой об интервью. Ссылка ведёт якобы на календарь, чтобы назначить удобное время 🔸 Во время белорусских протестов компаниям-партнёрам приходила рассылка: "Мы бастуем, поэтому к вам может прийти прокуратура с проверкой. Посмотрите по ссылке список интересующих их документов" 2️⃣ Сотрудник вышел из корпоративной сети, и дроппер скачал вредоносное ПО, который настроил удалённый доступ к компьютеру сотрудника. Но может сотрудник сделал всё сам. Плохие люди тоже встречаются. 3️⃣ В продакшн внедряются маячки из Cobalt Strike Cobalt Strike — это легальный инструмент тестирования безопасности, используется как безопасниками, так и хакерами. По статистике около 2/3 атак на крупные компании выполняется с помощью Cobalt 4️⃣ Удаляются резервные копии 5️⃣ Оставшиеся данные шифруются 6️⃣ Компании приходит письмо "Пришлите столько-то биткоинов на этот кошелёк и получите дешифратор". Иногда добавляются угрозы рассекретить информацию. Дальше всё зависит от инфраструктуры. Если у компании все бэкапы в одной подсети, и они уничтожены, то дело плохо. Всё хорошо, если остались репликации в других местах. ❓ Что с картами? Вайдберрис пишет, что эти данные защищены по стандартам PCI DSS. Но по слухам в Даркнет утекли данные 100к российских карт за последние 3 дня. Я на всякий случай перевыпустила свою карту. Надеюсь, в ближайшее время появится больше информации, и сама компания опишет ситуацию из первых рук. Тогда опыт Wildberries поможет другим компаниям🙏

Работа с задачами в Intellij iDEA Полезно для тех, кто часто переключается между задачами. 1️⃣ Для энтерпрайза В IDEA можно присоединиться к JIRA или другому таск трекеру, и у каждой задачи автоматически будет свой контекст. Контекст — это открытые вкладки и git ветка. Переключаетесь на другую задачу — автоматически открывается её набор вкладок и меняется ветка в гите. Есть интеграция с популярными таск трекерами: JIRA, Trello, Github, Bugzilla и тд Как подключить: File → Settings → Tools → Tasks → Servers → Плюсик в правом верхнем углу 2️⃣ Для личных проектов Можно сделать свой таск трекер внутри идеи: Tools → Tasks & Contexts → Open Task Дальше вводите название задачи. Их список затем доступен в правом верхнем углу. ОЧЕНЬ полезно, если вы часто переключаетесь между задачами и цените свои вкладочки🥰 У таск трекера в IDEA есть близкая фича — можно следить, сколько времени потрачено на каждую задачу: File → Settings → Tools → Tasks → Time Tracking → Enable Time Tracking IDEA показывает только полное время работы. Нельзя посмотреть статистику за день и внести её в корпоративный трекер, так что для рабочих проектов эта фича скорее бесполезна.

Основы Spring: жизненный цикл бина На тему жизненного цикла есть два доклада Жени Борисова: — Spring потрошитель (часть 1, часть 2) — Spring построитель Доклады замечательные, и документация у Spring прекрасная. Но у меня в своё время картинка не сложилась, пока я не составила простую схему. Немножко обновила её с тех времён, чтобы с вами поделиться🙂 Опишу стандартный случай — Spring Boot 5, базовые конфигурации, все бины определяются в коде и связываются через @Autowired. Основные участники: 🔸 Bean/бин/компонент — объект, которым управляет Spring 🔸 BeanDefinition — информация о будущем объекте. Имя класса, параметры конструктора и тд. 🔸 BeanFactory — отвечает за создание и хранение бинов 🔸 BeanPostProcessor (далее BPP) модифицирует бин после создания. У него два метода: — postProcessBeforeInitialization postProcessAfterInitialization 🔸 ApplicationContext — главный объект, хранит и вызывает все штучки выше Теория Что происходит и как туда внедриться: 1️⃣ Считывается информация из xml, yaml файлов Создаётся список BeanDefinition. Интерфейс — BeanDefinitionReader 2️⃣ Обработка BeanDefinition Дополняются параметры, определяется, кто от кого зависит и в каком порядке создавать бины. Интерфейс — BeanFactoryPostProcessor 3️⃣ Создаются экземпляры бинов Сначала создаются объекты @Component, потом @Bean (из классов-конфигураций). Для каждого бина порядок такой: ▫️ Вызов конструктора ▫️ Проставляются @Autowired зависимости над полями ▫️ Вызов set методов с @Autowired ▫️ Вызов методов интерфейсов *Aware ▫️ Все BPP, метод postProcessBeforeInitialization ▫️ Метод с аннотацией @PostConstruct ▫️ Метод afterPropertiesSet (если класс реализует интерфейс InitializingBean) ▫️ Метод, определенный в @Bean(initMethod = "xxx") ▫️ Все BPP, метод postProcessAfterInitialization. Тут обычно создаются прокси-классы ▫️ Бин добавляется в контейнер 4️⃣ Событие “контекст обновился” Ловится через реализацию интерфейса ApplicationListener<ContextRefreshedEvent> Или через метод с аннотацией
@EventListener
public void xxx(ContextRefreshedEvent contextRefreshedEvent) 

5️⃣ Запускается сервер 6️⃣ Событие "приложение запущено" Ловим событие ApplicationStartedEvent как в пункте 5 7️⃣ Логика в методе main, если у вас Spring Boot Менее популярные точки расширения: ▪️ Реализовать интерфейс *Aware ▪️ Поймать другие Spring Boot и Spring Core события Практика Точек расширения много, но что обычно используется: 🔸 Создать прокси-класс — BeanPostProcessor, метод after 🔸 Выполнить какую-то логику ДО старта сервера — поймать событие ContextRefreshedEvent 🔸 ПОСЛЕ старта сервера — событие ApplicationStartedEvent Часто разогрев кэша, service discovery и подобные задачи помещают в @PostConstruct, но на момент вызова не все бины могут быть готовы. При работе с событиями этой проблемы нет. И ещё пара рекомендаций: 🔹 Использовать одинаковые механизмы для одинаковых задач 🔹 Если в проекте больше трёх процессоров или задач на старте, упростите наблюдение за магией спринга. Это может быть файлик с описанием всех процессоров, очерёдностью и важными деталями. Или все процессоры поместить в одну папку. 🔹 Не помещайте бин процессоры и прослушивание событий в классы с бизнес-логикой. Нарушается принцип единственной ответственности, также могут быть проблемы с порядком обработки или количеством вызовов. ——— И небольшой апдейт по курсу: продлила скидос до 11 марта!

Смотрели доклад Spring потрошитель?
Anonymous voting

Основы Spring: что там происходит Когда я была джуниором, у меня было два этапа отношения к спрингу. Сначала "Вау, ставишь аннотацию и всё работает🥰". Но однажды аннотация не сработала. Было сложно разобраться, в чём дело, и уже через неделю я считала Spring порождением сатаны. Мне тогда не хватало общей картины, поэтому постараюсь составить её в этом посте. Spring стоит на трёх китах: 1️⃣ Dependency Injection Объекты в программе условно делятся на два вида: ▫️Компоненты — объекты, которые создаются в начале работы программы и обычно живут до конца. Контроллеры, классы сервисов, пулы соединений и т.д ▫️Данные — объекты, которые передаются между компонентами. Данные запросов, объекты пользователей, локальные переменные. Обычно живут в рамках одного запроса. Spring берёт на себя создание и связывание компонентов(или бинов). Это называется DI и упрощает жизнь разработчику. Spring — не единственный DI фреймворк. Подобные функции есть у Play framework, Dropwizard, Google Guice и т.д. Их часто используют тестировщики для автотестов. 2️⃣ Готовые компоненты Транзакции, асинхронное выполнение, ограничение доступа, работа с БД и очередями, облачные задачи. Spring предлагает готовые компоненты для большинства энтерпрайзных задач. Также Spring активно использует паттерн Декоратор (Wrapper, Proxy). От разработчика требуется минимум действий, которые хорошо описаны в мануалах. Как это выглядит. Допустим, в вашем классе есть метод doWork() с аннотацией Transactional. Spring сделает следующее: 🔸 Создаст прокси класс и переопределит метод:
public void doWork() {
   // начать транзакцию
   super.doWork(); 
   // закончить транзакцию
}

🔸 Создаст компонент с пулом транзакций и несколько промежуточных объектов. ✅ Минимум усилий от разработчика ❌ Сложно исправлять проблемы ❌ Большие накладные расходы. Spring создаёт и связывает сотни объектов на старте приложения, поэтому долго стартует и занимает много памяти 3️⃣ Кастомизация Можно написать свои аннотации или переопределить стандартное поведение. Не могу сказать, что это нужно каждый день, но раз в полгода-год появляются такие задачи. У спринга можно встроиться почти куда угодно. Это мы подробно обсудим в следующем посте. ✅ Легко встроиться в процесс ❌ Из-за этого сам процесс усложняется Именно комбо 1, 2 и 3 делает Spring таким популярным. Другие фреймворки предоставляют 1-2 пункта, но все три — только Spring. Самые популярные модули — MVC, Security, Data и Cloud. У каждого из них под капотом целый мир, и об этом тоже как-нибудь напишу.

Неделю назад я выложила анонс курса по многопоточке и получила немножко негатива на этот счёт. Я против любых убийств и любой дискриминации. Текущая ситуация — катастрофа для всех. Но в этом канале я пишу для java разработчиков и делюсь своим опытом. Если вам кажется это неуместным — отпишитесь. Курс тоже пройдёт по плану. Не вижу смысла его отменять. Ну а теперь к постам⬇️

Анонс курса по многопоточке Привет! Момент для анонса не самый удачный, но я надеюсь на лучшее🙏 Следую своему плану и стартую набор на курс по многопоточке! Кто давно ждал и уже готов → вам сюда А для тех, кто на канале недавно, расскажу подробнее. Курс строится вокруг java.util.concurrent. Изучим его в мельчайших деталях, как это перекладывается на практику и сравним разные инструменты между собой. Затронем и смежные темы: тестирование, флажки JVM, виртуальные потоки и реактивное программирование. Уроки выходят по расписанию 3 раза в неделю в предзаписи. Разберём огромное количество кейсов, лучших практик и возможных ошибок. Информации хватит для большинства многопоточных задач в энтерпрайзе. Уровень: middle/senior Старт: 21 марта Длительность: 8 недель Полная программа, отзывы(!) и запись тут: http://fillthegaps.ru/mt4 Зачем идти? ✅ Закрыть пробелы в базе. Java.util.concurrent — важная часть Java Core ✅ Работать на любых проектах. Многопоточка есть не только в хайлоад сервисах, а вообще везде. Просто обычно она прячется под слоем абстракций. ✅ Выбирать оптимальное решение для многопоточных задач, а не первое работающее со StackOverflow ✅ Круто выглядеть на собеседовании. Мало кто знает, зачем нужна модель памяти и как с ней работать на практике. Кандидат, который может это рассказать, сразу попадает в категорию "интересный"🙂 Сколько стоит? До 3 марта действует скидос: 🔸Тариф без обратной связи: 30000 23900 🔸Тариф с обратной связью: 45000 36900 Курс можно оплатить за счёт компании. Пусть ваши коллеги напишут на diana@fillthegaps.ru Если вы хотите закрыть этот пробел и разобраться с многопоточкой, и вам близок мой стиль изложения — записывайтесь, будет интересно! http://fillthegaps.ru/mt4

Настоящий сеньор Иногда в айтишных разговорах проскакивают фразы: — Я уже полгода сеньор, но чувствую себя мидлом — Вроде сеньор, но задачи делаю те же, что и раньше — Мне слишком много платят за ту ерунду, которую я делаю Это типичный синдром самозванца, и жить с ним неприятно. Что может помочь: 1️⃣ Признать текущие заслуги "Настоящий сеньор" — это как настоящий мужчина. Как будто он делает что-то особенное, чтобы стань "настоящим". Сеньором не делают заранее, должность выдают по факту. Будучи мидлом вы уже делали сеньорные задачи. Так что на текущем проекте вы точно на своём месте👍 2️⃣ Следить за общей ситуацией Даже если не хотите менять работу, полезно раз в полгода-год следить за рынком: ◾️ Обновить резюме и вписать последние достижения ◾️ Посмотреть 20 вакансий HeadHunter и наметить план развития ◾️ Походить по собеседованиям и увидеть свои пробелы. Если получится оффер, то самооценка взлетит до небес🙂 В одной компании тебя зовут в СТО, в другой даже джуниором не возьмут. Все проекты разные, и требования везде разные. Расскажу своё видение, чем отличается сеньор от мидла: Hard skills ▪️ Ориентироваться в популярных технологиях. Зачем нужны, плюсы-минусы, аналоги. Список технологий можно взять здесь. Он 2020 года, но ситуация не слишком поменялась ▪️ Настроить простой CI ▪️ Поднять систему с нуля с простой архитектурой (микросервисы, БД, очереди) ▪️ Работать с перфоманс проблемами. Знать, где посмотреть логи, что смотреть и как проверить, что проблема ушла ▪️ Целостное восприятие IT Тут сложно дать конкретный список. Просто очень странно выглядит сеньор, который не знает, что такое DNS и как масштабировать БД. Soft skills ▪️ Самостоятельность Сеньор может взять любую задачу и продвинуть её решение. Прикинуть, на каком уровне решать задачу (на фронте, в бизнес-логике, поправить конфиги, исправить ошибку в БД). Разбить на подзадачи и определить приоритеты. Сформулировать вопрос, если не хватает данных или компетенций. Предложить разные решения для разных требований ▪️ Контроль джуниоров и мидлов — провести онбординг и код-ревью, понятно отвечать на вопросы и делегировать подходящие задачи ▪️ Психологическая зрелость (не знаю как ещё назвать) — принимать решения в условиях неопределённости, признавать свою неправоту и незнание. Не заметать проблемы под ковёр и понимать приоритеты. Уважительно и продуктивно общаться. Понимать, когда устал/раздражён, и не принимать серьёзных решений в этом состоянии. Спокойно удалять свой код, если он не нужен. Но ещё раз — чётких стандартов нет. Каждый, кто уже стал сеньором, заслужил этот грейд, проделал большой путь и хорошо делал свою работу🔥

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

Интерфейсы, часть 2: методы по умолчанию Когда готовила материал по дефолтным методам, то перечитала почти все переписки разработчиков этой фичи. Огромное удовольствие — следить за спором опытных людей с высокой инженерной культурой и мощными теоретическими знаниями. Профессионализм завораживает🥰 Но я расскажу вам итог. В java 8 появилась новая возможность — методы с заданной реализацией:
interface Adapter {
   default int get() {…}
}

Класс, который реализует интерфейс, переопределяет такой метод при необходимости. ❓Зачем? 1️⃣ Облегчить изменения API Во времена java 7 в интерфейсах были только определения методов:
interface Collection<Т> {
   void add(Т);
   Т get();
}

Чтобы добавить, удалить или поменять сигнатуру метода нужно одновременно поменять код и в интерфейсе, и во всех реализациях. Если всё в рамках одного проекта, то проблем нет. Но если мы пишем библиотеку, то задача усложняется. Пользователи могут столкнутся с проблемами совместимости при переходе на новую версию. Задача дефолтных методов — сгладить этот процесс, предоставить приемлемую или временную альтернативу. В JDK основная цель дефолтных методов — поддержка Stream API в коллекциях. 2️⃣ Вспомогательные методы Которые не входят в прямую функциональность интерфейса, но их удобно добавить сюда, а не в каждый класс реализации. Нарушается принцип Interface segregation и часто похоже на костыль. Не одобряю, но такое встречается🙂 3️⃣ Комбинации базовых методов Мы обсуждали это в прошлом посте. В интерфейсе есть методы, которые по сути — комбинация других методов этого же интерфейса. Для таких комбинаций можно сделать статический метод. Он вызываются через имя интерфейса и недоступен у экземпляров. Если это неудобно, метод можно сделать как метод по умолчанию. Пример: интерфейс Comparator Цепочка из 2 компараторов — это 2 вызова compare и объединение результатов. Логика всегда одинакова, и нет смысла дублировать её в каждом подклассе:
default Comparator thenComparing(Comparator) {…};

❓Что если класс реализует 2 интерфейса с методами по умолчанию? Правила такие: 🔸 Если в классе переопределён метод по умолчанию — используется метод класса 🔸 Если один интерфейс наследуется от другого — используется метод наследника 🔸 В остальных случаях — ошибка компиляции Отсюда ответы на вопросы перед постом: 1️⃣ Ошибка компиляции 2️⃣ Напечатается В

Вопрос 2. Что выведется в консоль? (интерфейс В теперь расширяет интерфейс А)
Anonymous voting

Вопрос 2. Что выведется в консоль? (интерфейс В теперь расширяет интерфейс А)

Вопрос 1. Что выведется на консоль?
Anonymous voting