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 552 名订阅者,在 技术与应用 类别中位列第 10 101,并在 俄罗斯 地区排名第 52 755

📊 受众指标与增长动态

невідомо 创建以来,项目保持高速增长,吸引了 12 552 名订阅者。

根据 05 六月, 2026 的最新数据,频道保持稳定运转。过去 30 天订阅人数变化为 -49,过去 24 小时变化为 -4,整体触达仍然可观。

  • 认证状态: 未认证
  • 互动率 (ER): 平均受众互动率为 34.71%。内容发布后 24 小时内通常能获得 N/A% 的反应,占订阅者总量。
  • 帖子覆盖: 每篇帖子平均可获得 0 次浏览,首日通常累积 0 次浏览。
  • 互动与反馈: 受众积极参与,单帖平均反应数为 0
  • 主题关注点: 内容集中在 redis, hashmap, linkedhashmap, индекс, фича 等核心主题上。

📝 描述与内容策略

作者将该频道定位为表达主观观点的平台:
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк 🔥Тот самый курс по многопочке🔥 https://fillthegaps.ru/mt Комплименты, вопросы, предложения: @utki_letyat

凭借高频更新(最新数据采集于 07 六月, 2026),频道始终保持新鲜度与高覆盖。分析显示受众积极互动,使其成为 技术与应用 类别中的关键影响点。

12 552
订阅者
-424 小时
-257
-4930
帖子存档
Java 21: String templates Сегодня вышла java 20🥳 А в сентябре выходит java 21 (LTS) с интересной превью фичей — String templates. Про неё и расскажу в этом посте. Есть две стратегии работы со строками: 🔸 Конкатенация — собираем строку по частям из других строк:
String str = "Hello, " + name + "!";

Сюда же относится StringBuilder, метод concat и тд. 🔸 Интерполяция — замена переменных внутри шаблона:
String name = "Jake";
String str = "Hello, ${name}!";

В чистом виде в java такого нет. В Formatter и MessageFormat вместо переменных какие-то %s и %d, а переменные стоят отдельно:
String.format("%d plus %d equals %d", x, y, x + y);

Для сравнения, как это выглядит в Kotlin:
"$x plus $y equals ${x + y}"

Так вот, в java 21 появится интерполяция! В начале строки нужно добавить STR., а переменные поместить в \{}
int x = 10, y = 20;
String str = STR."\{x} + \{y} = \{x + y}";
// "10 + 20 = 30"

Хорошо работает вместе с текстовыми блоками (многострочные строки в тройных кавычках):
String name = "Joan";
String phone = "555-123";
String json = STR."""
{
   "name": "\{name}",
   "phone":"\{phone}",
}
""";

Внутри можно вызывать методы и писать блоки кода:
String time = STR."The time is \{
   DateTimeFormatter
    .ofPattern("HH:mm:ss")
    .format(LocalTime.now())
} right now";
//"The time is 09:01:45 right now"

Читаемость текста снижается, но если очень хочется — почему нет. ❓ Зачем нужен префикс STR? Почему нельзя просто добавить новый функционал в строки? Здесь 2 причины: 1️⃣ Для обратной совместимости На джаве написано много кода, и наверняка какие-то строки содержат блоки /{}. Будет обидно, если этот код перестанет компилироваться. Поэтому строки для интерполяции нужно явно обозначить 2️⃣ Может быть не только STR😱 Здесь открывается портал в другой мир. По задумке авторов темплейты могут подставлять переменные, валидировать данные и делать преобразования. Например, так:
JSONObject json = JSON."{ id: /{id}}";

или даже так:
ResultSet rs = DB."SELECT * FROM Person WHERE name = \{name}";

Для запросов в БД это, наверное, слишком, а вот для работы с JSON выглядит очень удобно. Но рано радоваться🙂 Из коробки этого не будет, только набор классов для кастомизации. Будем надеяться, что авторы библиотек возьмут фичу на вооружение. ❓ Как это работает? Выглядит как магия! В JDK появится статическое поле StringProcessor STR, а строка String str = STR."/{name}!"; во время компиляции превратится в StringTemplate template = new StringTemplate(паттерн, параметры); String str = STR.process(template); Cинтаксический сахарок и никакого волшебства✨

REST API — неоднозначная тема, по которой часто много вопросов и споров. В этом посте я кратко расскажу, что такое REST API и как он связан с REST. И что самое интересное — покажу принципы REST API на реальных примерах. Начнём сначала. REST — это набор архитектурных принципов, которую описал Roy Fielding в диссертации 2000 года. Один из тезисов гласит, что взаимодействие между системами должно крутиться вокруг понятия ресурса. REST API, в свою очередь, это набор рекомендаций для API: как составить URL-ы, что они принимают и возвращают. От REST здесь берётся только понятие ресурса. Остальное — частные интерпретации, в оригинальном документе ничего этого нет. Под REST API обычно понимают следующий набор правил: 1️⃣ В основе пути — существительное во множественном числе https://www.youtube.com/watch?v=123 https://rutube.ru/video/123 Множественное число встречается чаще, но на мой взгляд единственное тоже ок. Главное, чтобы в рамках проекта был единый стиль, и не смешивалось единственное и множественное 2️⃣ Иерархия ресурсов отражается в URL Например, в магазине одежды есть раздел с футболками. Как это отразить в API: https://www.lamoda.ru/c/2478/clothes-futbolki/ https://www.sportmaster.ru/catalog/zhenskaya_odezhda/futbolki/ 3️⃣ Желаемые действия с ресурсом определяются через HTTP методы Искусственный пример: ▫️ GET /users — вернуть список всех пользователей ▫️ GET /users/5 — получить пользователя с id=5 ▫️ POST /users — добавить пользователя ▫️ PUT /users/5 — обновить пользователя с id=5 целиком ▫️ PATCH /users/5 — обновить часть полей у пользователя с id=5 Найти идеальный реальный пример у меня не получилось, но очень близок оказался HeadHunter API по работе с резюме. Там всё по канону, но для редактирования они используют PUT. 4️⃣ Вызов методов GET, DELETE, PUT, PATCH должен быть идемпотентным Чтобы без проблем вызвать метод повторно, если что-то пошло не так 5️⃣ Методы PUT, POST and PATCH возвращают новый/обновлённый объект 6️⃣ Дополнительные параметры для метода GET указываются через ?, а тело метода остаётся пустым GET /resumes?text=java&age_from=18 – поиск совершеннолетних кандидатов, в резюме которых встречается "java" 7️⃣ Информация для POST, PUT, PATCH запросов передаётся в теле метода 8️⃣ В качестве ответа возвращается соответствующий HTTP код ▫️ 1хх: информационные сообщения, чаще всего служебные. Для бизнес-логики они не используются ▫️ 2xx: всё супер ▫️ 3xx: redirect ▫️ 4xx: ошибка на стороне клиента ▫️ 5xx: ошибка на стороне сервера Какие плюсы у REST API? Плюс на самом деле только один — в таком API проще разобраться. У Stepik REST API нет документации, но и так понятно, что GET /api/courses возвращает список курсов. Как видно по примерам, некоторые компании придерживаются подобных правил, некоторые — нет. Rutube более REST-API, чем Youtube, но для успеха продукта этого явно недостаточно🤭

Брейкпойнты в Intellij IDEA Когда я была джуниором-мидлом, проводила в дебаге 80% рабочего времени. Скучаю по временам, когда можно спокойно работать с кодом целый день. Не копаться в гигантских логах, не ходить на митинги по полдня, не делать код-ревью всей команды. Если вам доступно удовольствие писать код — цените его:) Большинство разработчиков пользуются только базовым дебагом в IDEA: щёлкнуть рядом с номером строки, чтобы добавить или удалить брейкпойнт. Чтобы отладка стала быстрой и приятной, есть 4 классные фичи: 1️⃣ Условия остановки Если метод часто вызывается, или брейкпойнт стоит в цикле, не тратьте время на ожидание нужных значений: 🔹Правый щелчок по брейкпойнту 🔹Добавить в Condition условие остановки — можно использовать все доступные переменные, объекты и методы 2️⃣ Изменение параметров в динамике Чтобы посмотреть, как меняются переменные, их обычно выводят в консоль через System.out.println. Более продвинутый вариант: 🔸Зажать Shift и добавить брейкпойнт 🔸Щёлкнуть галочку Evaluate and log 🔸Вписать нужное выражение Отладчик не будет останавливать выполнение, а запишет в консоль значение выражения. Незаменимая фича для отладки многопоточных приложений, кода сторонних библиотек и удалённого дебага! 3️⃣ Отключение брейкпойнта Ненужный брейкпойнт можно не удалять, а отключить: ▪️Щёлкнуть колёсиком по брейкпойнту ИЛИ ▪️Правый щёлчок по брейкпойнту → снять галочку с Enabled 4️⃣ Массовое удаление Когда в проекте много брейкпойнтов, IDE при дебаге немного тормозит. Чтобы удалить ненужные, откройте полный список: ▫️Правый клик по любому брейкпойнту ▫️Ссылка More ▫️Слева видим список брейкпойнтов ▫️Удаляем ненужные В этом окне ещё есть фильтры для выборочной остановки, но удобнее пользоваться условиями из первого пункта.

JUnit: самое важное Информация ниже не новая, но очень важная. Так что грех не повторить:) Ниже особенности и фичи JUnit, которые полезно знать большинству разработчиков. Если что-то заинтересовало и непонятно — поможет JUnit 5 User Guide 1️⃣ Жизненный цикл теста Каждый тест — это метод с аннотацией @Test. Через аннотацию @DisplayName задаётся симпатичное имя теста в отчёте. Чтобы выполнить что-то до или после выполнения теста, используются методы с аннотациями:
▫️ @Before, @BeforeAll
▫️ @After, @AfterAll

JUnit создаёт новый экземпляр класса на каждый тестовый метод. Класс ServiceTest с пятью методами @Test во время запуска превратится в 5 экземпляров класса ServiceTest. Благодаря этому тесты выполняются независимо. Этим JUnit отличается от TestNG, где создаётся один экземпляр класса на все тестовые методы. Если хочется как в TestNG, добавьте над классом аннотацию @TestInstance(Lifecycle.PER_CLASS) 2️⃣ Проверки Сердце каждого теста - методы с приставкой assert*:
🔸 assertTrue
🔸 assertEquals
🔸 assertInstanceOf

В самом JUnit мало методов, более удобные ассерты есть в библиотеках Hamсrest и AssertJ. AssertJ, на мой взгляд, более читабельный, но Hamсrest используется чаще. 3️⃣ Группировка тестов Аннотация @Tag("groupName") объединяет тесты в группы. Работает и для одного теста, и для класса. Можно указывать тэги в системе сборки и при запуске тестов из IDE. 4️⃣ Отключение тестов Аннотация @Disabled. Есть продвинутые варианты, можно отключить тесты для ▫️ операционной системы
@DisabledOnOs(WINDOWS)
▫️ версии java
@DisabledOnJre(JAVA_9)
@DisabledForJreRange(min = JAVA_9)
▫️ системных переменных:
@DisabledIfSystemProperty(named = "ci-server", matches = "true")
@DisabledIfEnvironmentVariable(named = "ENV", matches = ".*development.*")

5️⃣ Параметризированные тесты Помогают запустить один тест с разными аргументами. Выглядит так:
@ParameterizedTest
@ValueSource(ints={100,-14})
public void test(int input) {}

Такой тест запустится дважды - с аргументом 100 и -14. Вместо готового списка можно брать значения 🔸 из CSV файла @CsvSource 🔸 из метода @MethodSource 6️⃣ Проверка таймаута ▫️ Через ассерт
assertTimeout(ofMinutes(2), ()->{});
▫️ Через аннотацию
@Timeout(value=42,unit=SECONDS)

7️⃣ Полезные библиотеки ▫️ Hamсrest, AssertJ — расширенные библиотеки методов-ассертов ▫️ Mockito для заглушек. Добавляете библиотеку в pom.xml или build.gradle, а в тест - аннотацию @ExtendWith(MockitoExtension.class) ▫️ Testcontainers для запуска внешних компонентов в докере. Добавляем библиотеку, аннотацию @Testcontainers над классом и @Container над компонентом ▫️ Java Faker — генератор данных для тестов Ещё я когда-то писала 2 хороших поста на тему, чем отличается JUnit 4 от Unit 5. Если вас удивляет, почему там разные аннотации и почему версии не совместимы друг с другом, то почитайте:)

Java 20: новый костыль в HashMap На вопрос выше логично ответить new HashMap<>(1000). Сначала расскажу, почему этот ответ не походит. Потом наглядно покажу нарушение инкапсуляции, и что за костыль добавили в Java 20. Итак, что происходит внутри HashMap? Ячейки хэш-таблицы (или бакеты) хранятся в переменной Node[] table как простой массив. При вызове new HashMap() без параметров создаётся 16 бакетов. Если передать параметр с размером, то берётся ближайшая степень двойки. new HashMap(1000) создаёт массив из 1024 элементов. Кажется, что всё в порядке, но мы забыли про ребалансировку😒 HashMap хорошо работает, когда в каждом бакете 0 или 1 элемент. Тогда скорость поиска и добавления будет той самой О(1). Когда элементов становится больше, растёт шанс, что в один бакет попадёт несколько элементов. Поэтому в определённый момент HashMap удваивает количество бакетов и перераспределяет элементы. За момент, когда пора начать эту операцию, отвечает поле threshold. Его первое значение считается как [планируемое число элементов * 0.75], т.е когда HashMap заполнен на 3/4. При удвоении числа бакетов threshold тоже удваивается. И смотрите, что получается: 🔹 Мы хотим добавить в мэп 1000 элементов и вызываем конструктор с подходящим параметром initialCapacity: new HashMap(1000); 🔹 Создаётся 1024 бакета (ближайшая степень двойки) 🔹 Рассчитывается threshold: 1024*0,75 = 768 🔹 Добавляется 768 элементов 🔹 Приходит 769 элемент, начинается ребалансировка: ▫️ количество бакетов удваивается, теперь их 2048 ▫️ текущие элементы распределяются между ними ▫️ новый threshold удваивается, теперь это 1538 Что получилось: мы пообещали добавить в HashMap 1000 элементов. Сдержали обещание, но перестройка мэп всё равно произошла. Чтобы HashMap работал оптимально, нужно учесть ребалансировку и передать в конструктор, например, 1500. Надо знать детали реализации, чтобы получить то, что хотим. И это образцовое нарушение инкапсуляции🤌 В java 20 в HashMap добавили костыльный метод, который исправляет ситуацию: HashMap.newHashMap(1000); Внутри произойдёт вычисление 1000 / 0.75 = 1334, в итоге создаётся 2048 бакетов. Почему это костыль? Потому что исходная проблема не решается. Жизнь пользователя не становится легче, ему нужно запомнить "чтобы задать размер мэп — не пользуйся конструктором, пользуйся специальным методом". Хороший API — понятный, удобный и дружелюбный. Пользователю легко выбрать нужный метод, все параметры хорошо описаны в документации. Когнитивная нагрузка при использовании минимальна, нет подводных камней и обходных путей. Для собеседований сложно придумать вопрос с подвохом🙂 Важные заметки: 🔸 В JDK много образцового кода, и я рекомендую изучать исходники как можно чаще. HashMap — неприятное исключение 🔸 В ConcurrentHashMap всё хорошо. new ConcurrentHashMap(1000) сразу создаёт 2048 бакетов и не занимается лишними балансировками

Мы планируем поместить в HashMap 1000 элементов. Какое МИНИМАЛЬНОЕ число указать в конструкторе new HashMap<…,…>(❓), чтобы Map лишний раз не перестраивалась?
Anonymous voting

Книги для разработчиков Читать или не читать книги — вопрос индивидуальный. Огромное количество информации есть в виде статей, видяшек и туториалов. Для проработки точечных вопросов это отличный вариант. Книги — штука фундаментальная. Для выбранной темы вы получите последовательное изложение и множество деталей. В этом их огромный плюс. Заметила по себе и многим знакомым: чем старше по грейду становишься, тем больше тянет на книжки:) В посте поделюсь полезными приёмами по работе с книгами на примере Designing Data Intensive Applications. Она же "книжка с кабаном" или DDIA. Предварительный ресёрч Помогает понять, стоит ли тратить время на книгу, насколько интересны темы и подходят ли они вам по уровню. Лучше потратить один час на исследование, чем десятки часов на бесполезную или неактуальную книгу. Что можно сделать: 🔸 Пройтись по заключению к каждой главе Обычно это 1-2 страницы с концентратом информации и главными выводами 🔸 Посмотреть краткое содержание У популярных книг на youtube есть плейлисты с кратким содержанием. Чтобы найти — просто напишете в поиске название книги. Например, вот плейлист для DDIA. Каждая глава пересказывается за 10-15 минут. 🔸 Прочитать конспект Многие пишут конспекты по книгам и делятся ими с окружающим миром. Найти очень просто:
[название книги] summary

Хорошие конспекты по DDIA: покороче и подлиннее. Как прочитать книгу, в которой больше 10 страниц Большой объём часто вгоняет в тоску. Что может здесь помочь: 🔹 Читать в группе Объединиться с коллегами или друзьями и установить распорядок. Например, выбираете главу, которую надо прочитать за неделю, в пятницу созваниваетесь и обсуждаете прочитанное. 🔹 Присоединиться к читальному клубу Я знаю только один, сейчас они читают Art of Multiprocessor Programming и Effective Java. В крупных компаниях организуют похожие клубы, это надо узнать у HR. 🔹 Маленькие шаги Поставьте себе выполнимый план и придерживайтесь его. Допустим, каждый день читать по 10 страниц или по 20 минут. Важно удобно встроить чтение в вашу жизнь. Например, если после работы нет сил, то попробуйте читать до работы. 🔹 Не читать целиком Прочитать только интересную главу или пропускать главы, которые кажутся очевидными. Но если чувствуете высокий уровень книги, лучше прочитать полностью. 🔹 Не читать🙂 Если автор нудный или чтение идёт тяжело, можно взять темы из содержания и последовательно искать их на Youtube или в гугле. Не для всех книг подойдёт, но для некоторых норм. Что советуешь прочитать? Универсальных рекомендаций нет, всё зависит от текущих задач и ваших интересов. Джуниорам полезно прочитать Effective Java. Хочется погрузиться в недра БД — Database Internals. Активно следите за продом — Site Reliability Engeneering от гугла. Прочитали DDIA и хотите продолжения — Designing Distributed System. Разобраться в операционных системах или сетях — Таненбаум. Это я сама себе посоветую, а надо ли вам это читать — не знаю:) Спросите у старших коллег, они наверняка подскажут что-то релевантное вашему опыту и задачам проекта.

Читали Designing Data Intensive Applications (книжку с кабаном)?
Anonymous voting

Задачки на ООП На собеседованиях на middle позицию последнее время часто дают задачки на объектно-ориентированный дизайн. Определяется ситуация и требования, для них кандидат рисует диаграмму классов и определяет API. Код не пишется, но можно обсудить конкретные шаги для некоторых сценариев. Очень классный тип заданий! Занимают 15-30 минут, выполняются прямо на собесе, отлично проверяют прикладные навыки кандидата👌 Поделюсь тремя примерами для тренировки. 1️⃣ Библиотека У каждой книги есть несколько копий. Пользователь может взять до 5 книг на месяц. Затем он может продлить использование ещё на месяц. Если книги не возвращены в срок, система генерирует алерт. Если нужной книги в библиотеке нет, пользователь может её зарезервировать. Как только она появится, библиотекарь увидит сообщение “пользователь Х зарезервировал книгу Y”. Библиотекарь звонит пользователю X, и в течение 5 дней книга ждёт своего читателя. Напомню задание: определить API и нарисовать диаграмму классов. Усложнение: у библиотеки есть несколько филиалов. Пользователь может заказать книгу и сдать её в любой филиал. 2️⃣ Парковка На парковке доступно определённое количество мест. Они могут быть 3х размеров — S, M и L. На парковку заезжают транспортные средства разных типов — мотоциклы, легковые автомобили и грузовые. Они занимают места следующим образом: ▫️ S — помещается один мотоцикл ▫️ M — два мотоцикла или одна легковушка ▫️ L — 4 мотоцикла, 2 легковушки или один грузовичок Паркинг должен показывать количество свободных мест всех типов. При въезде транспортного средства ему нужно указать, на какое место встать. Чем плотнее заставлена парковка — тем лучше. Для каждого транспортного средства своя ставка. Также прайс зависит от времени стоянки. Например, для легкового автомобиля: 💲 первые 10 минут — бесплатно 💲 следующие 50 минут — 300 рублей 💲 1-3 час — 250 рублей в час 💲 3 час и далее — 200 рублей в час Оплата считается, когда транспортное средство покидает парковку. 3️⃣ Автомат с едой В автомате есть несколько слотов. В каждом слоте лежит товар с указанной ценой. В начале работы в автомате есть какое-то количество денег каких-то номиналов. Автомат принимает оплату картой и наличные, может выдавать сдачу. Если отдать сдачу невозможно, продажа отменяется, а деньги возвращаются покупателю. В автомате есть рулон с чеками. После каждой успешной транзакции покупателю выдаётся чек. Нет чеков — продажа не совершается. В системе три роли: 👨 Оператор. Ставит новый рулон с чеками, балансирует наличные деньги 🙎‍♂️ Покупатель. Выбирает товар, способ оплаты и вносит деньги. При оплате наличными получает сдачу. Если сдачи нет, забирает свои деньги назад. Если всё ок, покупатель забирает чек и товар 🤵 Менеджер. Видит статистику по операциям и балансирует наличку Таких задач море: бронь мест в отеле или билетов в кинотеатре, дизайн StackOverflow или Twitter как монолитного приложения, имитация шахмат или покера. Плюс огромное количество вариаций и усложнений. Если вы только подбираетесь к Junior позиции, можете взять эти примеры как основу для пет-проекта. Добавьте Spring, БД, потокобезопасность, юнит-тесты — и проект для портфолио готов👌

Последний день для ранних пташек Сегодня последний день, когда можно вписаться на курс как early bird🦅 Курс строится вокруг java.util.concurrent — боевой лошадки каждого нагруженного сервиса. В деталях изучим все классы, концепты и практическое применение. Разберём огромное количество кейсов, лучших практик и возможных ошибок. Ну и по мелочи — разберёмся с тестированием многопоточки, сравним разные подходы (реактивщина, Project Loom, корутины), подготовимся к собеседованиям. Всё шаг за шагом и с картинками:) Курс точно нужен, если вы: ▫️ Знаете основы многопоточности, но чувствуете, что этого недостаточно ▫️ Хотите уверенно решать задачи на любых проектах, знать об актуальных решениях и основных ошибках ▫️ Хотите проходить сложные собеседования и вписываться в интересные проекты Must have для разработчиков, которые мало работали с многопоточкой, но готовы закрыть этот пробел за 2 месяца. Курс — это концентрат знаний и продуманный маршрут по их освоению. 👨‍🦱 “Большое спасибо за такой крутой курс, ничего подобного в обучении я не видел, с такими людьми как вы хотелось бы работать в одной команде)” 👨‍🦱 “Даже если вы читали "Java Concurrency in Practice" , вы узнаете что-то новое” 👨‍🦱 “Это один из лучших курсов по Java, который проходил. Хоть курс и предназначен для тех, кто хочет дополнить знания по многопоточке (middle/senior), но в ходе прохождения понял, что его следует давать всем разработчикам. Курс полностью посвящён всем областям многопоточного программирования на Java, с которыми сталкивается разработчик, даже немного выходит за рамки, но ценнее всего, что он расширяет кругозор разработчика и дает ему прикладные примеры (best practices)” 👨‍🦱 “Что понравилось: - изложение материала, насыщенность лекций; - задания: разноплановость, необычный ракурс, анализ реального кода (нужно брать курс с обратной связью, симулирует глубже погружаться в тему и добивать до понимания); - динамика курса.” Старт: 13 февраля Длительность: 9 недель Завтра цена вырастет, присоединяйтесь сегодня! http://fillthegaps.ru/mt7

Форматы обучения Сегодня чуть подробнее расскажу про формат и внутрянку курса! Помните декабрьский адвент? Он занимал мало времени и отлично справился со своей задачей: повторить материал или закрыть небольшие пробелы. Поэтому я так часто повторяла, что это не курс. В случае с курсом подход другой. Его задача — научить человека правильно пользоваться java.util.concurrent. Поэтому каждая тема разбирается до мелочей и обязательно закрепляется на практике. Как выглядит каждый урок: ▫️ Небольшая лекция (до 20 минут) ▫️ Тесты на закрепление и вопросы с собеседований ▫️ Практика: решение типовых энтерпрайзных задач и код-ревью уже написанного кода В среднем прохождение занимает 4 часа в неделю. Вся учёба идёт асинхронно, вы сами решаете, как распределить нагрузку по неделе. 👨‍🦱 “Курс очень плотный и нельзя расслабляться, совмещать с работой и прочим бытом непросто, но все реально. Главное не копить это на конец недели, а делать понемногу каждый день” 👨‍🦱 ”Приготовьтесь, вы будете очень много слушать, читать и перечитывать, ковыряться в доках, в исходниках библиотек, перевернете весь интернет в поисках ответов на уточняющие вопросы” 👨‍🦱 ”Насыщенные домашние задания. Не "повтори услышанное за преподавателем" и не "а не вольтметром ли измеряется напряжение", часто приходилось действительно попотеть. Вопросы отчасти перекрываются с материалом лекций, а отчасти расширяют его, что особенно круто - когда что-то откопал своими усилиями, запоминается оно гораздо лучше” Варианты обучения: 1️⃣ С обратной связью (моей) Самый эффективный способ. Проверяю все практические задания, вижу именно ваши пробелы и помогаю их устранить. 👨‍🦱 “Я бы брал курс с обратной связью, так как преподаватель задает вопросы на понимание используемых инструментов и процессов, что мотивирует лучше разобраться в теме” 👨‍🦱 ”Обратная связь - самая сильная и самая замечательная часть этого курса, что означает, что, даже если в теме что-то не устраивает, всегда можно спросить по интересующим именно вас моментам” 👨‍🦱 ”Задачи больше на понимание, с подводными камнями, комментарии преподавателя бесценны 😍 Не нужно писать тонны кода, но нужно разобраться, что происходит, и залезть в документацию” Размер группы ограничен, сейчас осталось 12 мест 2️⃣ Без обратной связи Основной педагогический челлендж любого курса — организовать адекватную самостоятельную работу. Практические задания на этом тарифе тоже есть, но требуют больше вовлечения от ученика. Для заданий с кодом есть юнит-тесты и примеры реализаций. Для код-ревью — набор вопросов, которые помогут прийти к верному решению. Например, даётся код и к нему вопросы: ❓ Какие гарантии даёт метод А? ❓ У какого объекта захвачен монитор в методе Б? ❓ А в методе Ц? И только потом ❓ Какие проблемы возможны в этом коде? Путь к ответу длиннее, но более последовательный. По статистике ответов такой подход работает лучше! Путь к успеху — не забивать на непонятные моменты и стараться найти ответ в предложенных материалах. Если вы дисциплинированы, готовы разобраться в многопоточке и потратить меньше денег, то возьмите тариф без обратной связи, он тоже классный! Запись на оба тарифа здесь → http://fillthegaps.ru/mt7

Набор на курс Многопоточное программирование Привет! И вновь открывается набор на курс по многопоточке! Старт: 13 февраля Длительность: 9 недель Кто давно ждал и уже готов → вам сюда Теперь подробнее. У курса две основные задачи: ✅ Научиться писать хороший многопоточный код Разберём типовые энтерпрайзные задачи, огромное количество кейсов, лучших практик и возможных ошибок. Будем сравнивать производительность разных решений для разных ситуаций. ✅ Подготовиться к собеседованиям, где требуется concurrency Обсудим стандартные и нестандартные вопросы, порешаем тестовые задания. Что говорят ученики: 👨‍🦱 “Курс понравился тем, что он "от разработчиков разработчикам": примеры реальных библиотек для разбора, приближенные к реальным задачи для кодинга” 👨‍🦱 ”Курс очень интенсивный, охватывает не только многопоточку, но и смежные темы, учит разным лайфхакам полезным для практического использования, обращает внимание на темы, которые легко или упустить, изучая тему самостоятельно, или вообще можно никогда не узнать без курса” 👨‍🦱 ”Есть очень много свежей информации, которую сконцентрировано в едином источнике не получить” 👨‍🦱 “Это не с нуля совсем курс, и больше про правду разработки, разбавленную вопросами с собесов, а не про чистые знания.” Все отзывы можно прочитать на сайте. Для какого уровня курс? Middle и выше Сколько стоит? До конца пятницы (27.01) цена такая: 🔸 Без обратной связи: 24900 30000 руб. 🔸 С обратной связью: 44900 60000 руб. ✔️ Есть рассрочка на 3 и 6 месяцев ✔️ Принимаются карты любых банков ✔️ Курс можно оплатить за счёт компании — пусть ваши коллеги напишут на diana@fillthegaps.ru Аналогов у курса нет. Вообще:) С каждым потоком программа становится лучше, задания интереснее, а учёба приятнее. Если хотите разобраться с многопоточкой, и вам близок мой стиль изложения — записывайтесь, будет очень полезно! http://fillthegaps.ru/mt7

Оптимизация запросов В этом после хочу рассказать основы оптимизации запросов в БД. Буду говорить на примере Postgre, но в других БД процесс похож. Шаг 0. Вспоминаем основы При выполнении запроса участвуют два процесса: ▪️ Планировщик — составляет план выполнения запроса. Какие таблицы обойти, что проверить и в какой последовательности ▪️ Исполнитель — извлекает данные по заданному плану Разработчик может создать дополнительные структуры данных — индексы. Индексы помогают быстрее выполнять запросы, но занимают много места. Если данные в таблице занимают 1 ГБ, то индекс с id займёт 250 МБ. Шаг 1. Ищем, что оптимизировать Смотрим таблицу pg_stat_statements — там собирается статистика по запросам. Чтобы получить достоверные данные, берём статистику с продакшн базы. Ищем запросы, которые выполняются часто или долго. Шаг 2. Работаем с конкретным запросом Для экспериментов берём тестовую базу с большим количеством данных. Минимум миллион записей, иначе эффект оптимизаций не будет заметен. Прогоняем запрос через EXPLAIN ANALYZE:
EXPLAIN ANALYZE SELECT * FROM users where name = ’K’;

EXPLAIN пишет только план выполнения запроса. EXPLAIN ANALYZE выполняет запрос и показывает ▪️ planning time — время планирования запроса ▪️ execution time — время выполнения запроса. Работаем с этим значением Можно поиграть с условиями, порядком соединения таблиц и разными функциями. Обратите внимание на способ обхода таблицы: Index Scan using name_index on — при выполнении запроса используется индекс, и это отлично Seq Scan on означает, что происходит долгий последовательный обход таблицы. Причиной может быть 🔸 поиск по условию (where name = …) 🔸 проверка уникальности поля 🔸 проверка внешнего ключа (foreign key) Решение здесь простое — добавить индекс по проблемному полю. Базовый вариант выглядит так:
CREATE INDEX index_name ON users(name);

Дальше всё просто: ▫️ Запустить EXPLAIN ANALYZE ▫️ Увидеть в плане выполнения новый индекс ▫️ Порадоваться снижению execution time Для оптимизаций популярных и тяжёлых запросов добавление индекса оправдано. Разумеется, не нужно добавлять индексы для всех запросов и всех условий. Индексы занимают много места и замедляют запись в базу. В оптимизации запросов огромное количество нюансов, но большинство проблем решается кэшем и добавлением индекса. Более сложные случаи лучше обсуждать с коллегами DBA😌

Типы кэшей Если спросить разработчика, что такое кэш, он скорее всего ответит: — Кэш — хранилище типа ключ-значение. Позволяет снизить количество запросов к БД, другому сервису или не выполнять повторно сложные вычисления Это, безусловно, правда, но не вся. В этом посте кратко опишу, что ещё умеют делать кэши и какие они бывают. 1️⃣ Кэш внутри сервиса Хранится только в оперативной памяти. При выключении сервиса кэш пропадает. При включении — заполняется. Популярны два варианта: 🔸 ConcurrentHashMap: полностью ручное управление. Разработчик пишет код по наполнению кэша, обновлению и удалению значений 🔸 Google Guava Cache: более продвинутый вариант. Очищает кэш, уведомляет об удалении, предоставляет статистику 2️⃣ Удалённый кэш Не связан с конкретным сервисом и запущен в отдельном процессе ✅ Доступен для нескольких сервисов ✅ Хранит данные на нескольких уровнях — в оперативной памяти и на диске 3️⃣ Распределённый кэш Данные хранятся в нескольких процессах. Один экземпляр обычно называют нодой ✅ Шардирование. Распределяем данные по разным нодам и в итоге храним больше данных ✅ Репликация. Дублируем данные на разные ноды и повышаем доступность Уровни 2-3 это скорее ступени эволюции кэшей. Большинство реализаций находятся на уровне 4: 4️⃣ In-memory data grid (IMDG) Распределённый кэш с дополнительными фичами. Например: ▫️ Атомарный апдейт (вместо чтения и перезаписи) ▫️ Подписка на изменения в кэше ▫️ Поддержка транзакций ▫️ SQL-like запросы ▫️ Средства синхронизации (распределённый lock, очередь) ▫️ Продвинутый мониторинг ▫️ Выполнение скриптов У многих кэшей есть платная и бесплатная версии. Многие фичи из списка выше доступны только платно. В вакансиях чаще всего встречается Redis, чуть отстаёт Hazelcast. Также видела в проектах Memcached, Ehcache, Aerospike, Ignite/GridGain, Coherence. В их описании нет слова "кэш", как минимум distributed real-time in-memory streaming data platform🙂 Рекомендую погулять по документации того же Redis или Hazelcast, может для вашего проекта найдётся что-то полезное.

Hashcode для Hibernate сущностей Год новый, а темы всё те же. В декабрьском адвенте разгорелась горячая дискуссия на тему hashcode. Встал такой вопрос: Как определить hashcode для сущностей Hibernate? Что делать, если объект пока не сохранён в БД и у него нет id? В этом вопросе часто упоминается статья Thorben Janssen Ultimate Guide to Implementing equals() and hashCode() with Hibernate В самом конце там вывод: если для сущности id генерируется в БД, то hashcode должен возвращать константу. Почему это не лучший вариант? Контракт соблюдается, всё работает корректно. Но задача хэша — быстрая проверка схожести объектов. Мы теряем преимущество быстрого поиска, и хэшсет будет работать как список. Так будет и для новых объектов, и для уже сохранённых (у которых id есть). Другие авторы рекомендуют считать хэш Hibernate сущностей на основе всех полей кроме id. В чём недостатки такого решения: ❌ Если поля изменяемые, есть шанс потерять объект внутри HashSet ❌ Цель хэша — быстрая проверка. Если считать хэш всех полей, с тем же успехом можно использовать списки и сравнение через equals Что же делать? 1️⃣ Использовать для хэша любое неизменяемое поле Даже если поле не уникальное, распределение хэшей будет лучше, чем у константы 2️⃣ Не использовать хэш-структуры для новых объектов Новые объекты собирать в список:
List users = …
users.forEach(u -> session.save(u));

Тогда в хэшкоде можно спокойно использовать id и для уже сохранённых объектов хэшсет будет работать как надо:
Set users = …
if (!users.contains(…)) {…}

Итого: 🔸 Hashcode нужен только, когда структура используется в hash-based структурах. Если новые объекты не складываются в HashSet или HashMap, то проблемы вообще нет 🔸 Если вы хотите возвращать в хэшкод константу, рассмотрите вариант хранения сущностей в ArrayList или TreeSet Ответ на вопрос перед постом: зависит от сценариев использования. Если новые объекты User собираются в коллекцию, я бы складывала в список, а hashcode реализовала как return id; Но ситуации бывают разные, решение не универсально. И более глобальные выводы: Хороших материалов по разработке мало. Но даже в хороших легко свернуть не туда. Статья Thorben Janssen в целом ок, но итог немного сбивает с толку. Сравните: 💁🏼‍♂️ "Если для сущности id генерируется в БД, hashcode должен возвращать константу" 💁🏼 "Если новые Hibernate сущности складываются в hash структуры, и у них нет final полей, то для соблюдения контракта можно использовать в hashcode константу" Второй вариант корректнее, но первый проще и лучше запоминается. Не попадайте в эту ловушку. Задача разработчика — разобраться в сценариях, оценить варианты и найти подходящий😌

Как бы вы определили метод hashcode для этого класса?
Anonymous voting

Для работы с сущностями User используется Hibernate. Как бы вы определили метод hashcode для этого класса?

Итоги Закончился последний рабочий день в этом году! Наконец-то можно подвести итоги и отдохнуть. Начну с чуть запоздавших итогов адвента. Участников: 1787 До конца дошло около 350 человек 🏆 Отзывов с 5 звёздочками: 118 (!!!) Плюс огромное количество приятных комментариев и сообщений. Сердечко таяло, щёчки краснели, спасибо🥰 Спасибо вообще всем подписчикам! Что читаете посты, ставите реакции и задаёте вопросы. Рада делиться знаниями и получать приятный фидбэк. Вы лучшие! Пусть в следующем году у вас всё будет хорошо. Пусть работа приносит удовольствие и много денег, выгорание обойдёт стороной, а жизнь за пределами работы наполняет энергией С наступающим новым годом!🎄

Статистика адвента, выпуск 3 На прошлой неделе открылись темы: ❄️ Коллекторы Stream API ❄️ Списки ❄️ Копии коллекций ❄️ Методы Map ❄️ Причуды Map ❄️ Records ❄️ Pattern matching Участников: 1680 ❤️ Отзывов с 5 звёздочками: 21 (спасибо!!!!!) Формат адвента мне нравится больше, чем посты. Можно шире развернуть мысль, добавить больше примеров. Участникам тоже веселее — любой интерактив приносит больше пользы, чем просто чтение поста. Может однажды руки дойдут до полноценного курса по кору. С внутрянкой JVM, лучшими практиками, разбором кейсов, концепций и тд. Знаю, что могу сделать бомбическую штуку. Не знаю, будет ли на это время:) Напоминаю, что завтра в адвенте откроется последнее окошко, а во вторник всё закроется. Не откладывайте🏃‍♀️ 🏃

Статистика адвента, выпуск 2 На второй неделе открылись темы: ❄️ Микрооптимизации String ❄️ Сложение строк ❄️ Исключения ❄️ Блок try-catch ❄️ Дженерики ❄️ Дженерики в коллекциях ❄️ Интерфейс Supplier ❄️ Optional ❄️ Stream API Участников: 1581 ❤️ По расписанию идут около 200 человек. Ещё 300 идут стабильно, но не ежедневно. На вопрос "какая нагрузка у вас на работе под конец года?" получила такие ответы: 🙃 19% Расслабленная атмосфера 🙂 42% Как обычно, все по плану (я тоже тут) 😬 20% Всё не по плану, но справляемся 😰 17% Работы сильно больше, доделываем всё перед праздниками Много статистики скопилось по прохождению адвента мальчиками/девочками и разными грейдами. Здесь пока подержу интригу. Ещё из новостей: закончился 6 поток курса по многопоточке. Осень была для многих непростой (мягко говоря), очень горжусь теми, кто нашёл силы на учёбу💪 Следующий поток запланировала на февраль. Такие вот краткие сводки. Весь движ сейчас в адвенте, все силы тоже там:)