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
帖子存档
10 правил безопасных java приложений. Скорость, масштабируемость, удобство использования — такие требования обычно ставят заказчики. Устойчивость к атакам и защита данных редко проговаривается и подразумевается по умолчанию. Для кода на java есть много рекомендаций, например, Secure Coding Guidelines for Java SE. На практике большинство ошибок можно избежать очень просто: 1️⃣ Понятный код и однозначная бизнес-логика - уязвимости легко пропустить в чём-то сложном и запутанном. Сужайте и скрывайте доступную функциональность на всех уровнях: 🔸 Модификаторы полей и классов: всё, что может быть private, делайте private. Если для задачи удобно поменять private на public, подумайте о других вариантах. 🔸 Reflection и проверка имён классов: используйте осторожно, т.к такой код не адаптируется к изменениям. Поменяется имя метода, добавится ещё один класс, а рефлекшн останется тем же. 🔸 Внешний API: чем проще, тем лучше. 2️⃣ Избегайте сериализации: чтобы хранить и передавать объекты внутри системы используйте облегчённые протоколы с поддержкой версионирования: gRPC, Avro, Thrift и т.д. 3️⃣ Шифруйте персональную информацию: пароли, номера карточек, кодовые слова. Не записывайте её в лог! В 2019 году перехват незащищённых данных всё ещё входит в топ-3 опасностей по версии OWASP. 4️⃣ Проверяйте входные данные от пользователей и сторонних систем. Даже если похожие проверки есть на фронтенде. Ограничивайте размер пользовательского ввода и результатов: не позволяйте загружать 5 ГБ картинку и запрашивать триллион записей. 5️⃣ Используйте PreparedStatement для запросов к БД. Для большинства NoSQL они тоже есть. 6️⃣ Скрывайте технические детали в сообщениях об ошибке: не показывайте стек трейс конечному пользователю и в консоли браузера. 7️⃣ Обновляйте библиотеки, не игнорируйте авто-апдейты. 8️⃣ Проверяйте open-source библиотеки, которые используются на проекте, например, с помощью OWASP Dependency-Check. Коммит вредоносного кода в open-source - реальная угроза. 9️⃣ Записывайте и анализируйте активность пользователей - как минимум неудачные попытки авторизации. 🔟 Тестируйте методы на переполнение, оно случается.

Stream API: забудьте про peek() Один из недостатков Stream API по сравнению с циклами - неудобный дебаг. До сих пор метод peek() был единственным способом посмотреть элементы внутри стрима:
list.stream().filter(..)
.peek(e->println("filt:"+e))
.map(..)
.peek(e->println("map:"+e))
...

Недавно в Intellij IDEA вышел потрясающий апдейт, который выводит дебаг стримов на новый уровень:

Stream API: обзор и основные методы. Stream API - удобный инструмент обработки данных, который появился в java 8. Два принципа, на которых строится Stream API - composition & single responsibility. Действия собираются из простых независимых друг от друга блоков без сайд-эффектов. Этим достигается удобство чтения и поддержки: ✅ Стандартные названия. ✅ Нет локальных переменных. ✅ Линейная последовательность действий. Стрим состоит из 3 частей: 1️⃣ Источник данных. 2️⃣ Преобразования. 3️⃣ Конечная операция. Основные способы создать стрим: 🔸 Из готовой коллекции 🔸 Из набора элементов 🔸 Из массива 🔸 Задать первый элемент и правило вывода последующего, получится бесконечный стрим: Stream.iterate(T, BinaryOperator) 🔸 Задать первый элемент, правило вывода последующего и условие остановки: Stream.iterate(T, Predicate, BinaryOperator) (java 9) 🔸 Генерировать независимые друг от друга элементы: Stream.generate(Supplier) 🔸 Из диапазона с включением граничных значений: IntStream.range(..) 🔸 Диапазон без граничных значений: IntStream.rangeClosed(..) 🔸 Из строк: BufferedReader.lines() 🔸 Из символов строки: CharSequence.chars() Названия большинства методов преобразований говорят сами за себя: filter, distinct, limit, sorted. Есть менее понятные: 🔹 map: применить функцию к каждому элементу. 🔹 flatmap: положить элементы из "списка списков" в единый стрим. Также с его помощью можно уменьшить размерность массива. 🔹 takeWhile(Predicate): брать элементы из стрима, пока выполняется условие. Метод доступен c java 9. 🔹 dropWhile(Predicate): пропускать элементы, пока условие не нарушится. Метод доступен c java 9. 🔹 peek(Consumer): сделать что-то с каждым элементом стрима, не меняя исходный стрим. Часто используется при дебаге, например, вывести в консоль текущие элементы. Вычисления выполняются не сразу, а только когда вызывается конечная операция. Конечная операция описывает желаемый результат. Результатом может быть: ◾️ Структура данных: toArray, collect. ◾️ Результат поиска: anyMatch, allMatch, nonMatch, findFirst, findAny. ◾️ Результат агрегации: min, max, count, reduce. ◾️ Сайд-эффект: forEach, forEachOrdered. Стрим - не структура хранения данных. Он обходит источник данных (или сам его генерирует) и сохраняет промежуточные результаты. По этой причине нельзя копировать стримы и исполнять их несколько раз - пришлось бы контролировать этапы исполнения, консистентность данных и добавить синхронизацию для работы в многопоточной среде. При попытке переиспользования стрима выбрасывается IllegalStateException. ✅ Исходные данные не меняются. ✅ Стрим нельзя переиспользовать. ✅ Пока не вызвана конечная операция, стрим можно менять как угодно. Пример из опроса выше вернёт 1. list.remove(0) удаляет элемент с индексом 0, поэтому на момент старта вычислений stream.count() в источнике данных остаётся всего один элемент. Если Вас раздражает, что метод list.remove принимает не сам элемент, а индекс, то некоторые методы Stream API Вас тоже разочаруют. Например, такой код компилируется:
Stream.of(-1, 0, 1).max(Math::max).get();
Но в результате получается -1, потому что входной параметр метода max - Comparator. Math.max по сигнатуре на него похож, поэтому получается неверный результат😒

Ответ:
Anonymous voting

Что выведет следующий код? List list=new ArrayList(); list.add(1); list.add(2); Stream stream=list.stream(); list.remove(0); println(stream.count());

java.util.Set: сравнение реализаций. Set - интерфейс для коллекций из уникальных элементов. В стандартной библиотеке java 6 реализаций: HashSet, TreeSet, LinkedHashSet, CopyOnWriteArraySet, ConcurrentSkipListSet и EnumSet. В этой статье рассмотрим и сравним первые три из них. Детали реализации: 1️⃣ TreeSet базируется на TreeMap, а он - на основе красно-чёрного дерева. Элементы коллекции должны реализовать интерфейс Comparable, либо экземпляр Comparable нужно передать в конструкторе, потому что compareTo - основной метод для вставки и поиска элементов. ✅ Отсортированные значения. ✅ Быстрая ребалансировка. ✅ Можно искать по ближайшему ключу - доступны функции lower(e), floor(e), ceiling(e), higher(e). 2️⃣ HashSet внутри себя содержит HashMap. Он реализован так: Есть массив корневых элементов - их ещё называют бакетами. Размер массива по умолчанию 16. Если нужно добавить элемент в коллекцию, то сначала вычисляется его хэш. Далее ищется индекс корневого элемента - остаток от деления хэша на размер массива. Если по этому индексу ничего нет, корнем становится новый элемент. Если есть - добавляется в структуру под ним. В java 7 этой структурой был список, с java 8 - бинарное дерево. Эффективность HashSet зависит от равномерности распределения хэшей. В энтерпрайз приложениях хэш вычисляется по набору полей, и равномерность часто не достигается. Поэтому на практике HashSet не всегда является оптимальной структурой данных. Если известно примерное количество элементов, можно задать loadFactor и capacity в конструкторе. ✅ Возможность оптимизации. ✅ Быстрый поиск. ❌ Значения не отсортированы. ❌ Долгая перестройка при увеличении размера коллекции. 3️⃣ LinkedHashSet расширяет класс HashSet. Помимо основной структуры новые элемент также добавляются в двусвязный список. ✅ Значения отсортированы по порядку вставки. ✅ Возможность оптимизации. Знание деталей реализации даёт простые правила выбора: 1️⃣ Частый поиск - выбираем TreeSet. 2️⃣ Порядок не важен - HashSet. 3️⃣ Порядок вставки важен - LinkedHashSet. Мы проверили, насколько велика разница между реализациями: 1️⃣ Добавить в Set миллион чётных чисел. 2️⃣ Вставить миллион нечётных. 3️⃣ Найти миллион случайных. Запустили несколько раз для HashSet, TreeSet, LinkedHashSet, а также для HashSet и LinkedHashSet с заранее заданной ёмкостью в 2 миллиона. Проверили на java 7 и 11. В качестве типов данных использовали Integer(идеальное распределение хэшей) и класс с несколькими полями (неравномерное распределение). Результаты на картинке внизу поста. Тест не претендует на точность, но теперь можно добавить ещё несколько рекомендаций: ✅ В новых версиях java все операции всех реализаций работают на 5-20% быстрее. ✅ Выбор реализации имеет значение. ✅ Знаете будущий размер коллекции - передавайте его в конструкторе. ✅ Для чисел лучше использовать HashSet. ✅ Для экземпляров классов всё неоднозначно, имеет смысл попробовать разные варианты.

Сколько реализаций интерфейса Set в пакете java.util?
Anonymous voting

Функциональный стиль в java: когда он нужен? Большинство задач в энтерпрайзе делятся на две группы: 1️⃣ Одиночный запрос. Покупка в интернет-магазине, вывод курса доллара — такие запросы затрагивают мало данных и много компонентов. Эти бизнес-процессы хорошо описываются объектами и отношениями между ними. 2️⃣ Обработка данных. Статистика покупок, поиск рекомендаций, прогноз погоды - в центре внимания обработка данных, а не взаимодействие сущностей. Задача разработчика — чтобы обработка была быстрой. Нужно по максимуму использовать ресурсы процессора и доступную память, снизить время простоя и количество блокировок. Вот здесь пригодятся некоторые подходы функционального программирования(ФП) : 1️⃣ Понятие чистой функции. В многопоточном программировании главная проблема — работа с общими переменными. Чтобы безопасно их обновлять и всегда читать актуальные знвчения используются средства синхронизации. Большинство из них снижают общую пропускную способность. Чистые функции - методы, которые характеризуются только входными и выходными данными. У них нет сайд-эффектов, Они не меняют внешних объектов и не бросают эксепшены. Для одинаковых входных данных результат всегда будет один и тот же. ✅ Нет общих переменных — нет синхронизации. ✅ Можно кэшировать некоторые результаты. 2️⃣ Неизменяемые данные Исходные данные не должны меняться. Меняться могут только локальные переменные. ✅ Синхронизация не нужна — общие переменные не меняются и всегда актуальны. Пример: добавление элемента в список. Подход ООП: добавляем в исходный список - меняем внешний объект. public void add(List list, Integer value) { list.add(value); } ✅ Минимальный расход памяти. ❌ Для запуска в многопоточной среде нужна синхронизация. ❌ Если метод прервался, то нужно выяснять, что он успел изменить, а что нет. Подход ФП: создаём новый список на основе исходного и добавляем туда элемент. public List add(List list, Integer value { List newList=new List(); newList.addAll(list); newList.add(value); return list; } ✅ Можно использовать в многопоточной среде. ✅ Если что-то пошло не так, просто ещё раз вызываем метод. ❌ Большой расход памяти. 3️⃣ Декларативный стиль написания кода. Обход коллекции в цикле — это императивный подход. Для каждого элемента задаётся чёткая последовательность действий. Stream API — декларативный. Благодаря большому количеству встроенных функций можно просто описать то, что нужно: отфильтровать, сгруппировать, просуммировать. Лучшая читаемость - не единственное преимущество такого подхода. Чистые функции и неизменяемые данные сами по себе тоже не сделают программу эффективной. Но их использование в Stream API дают компилятору и JVM большие возможности для оптимизаций. Cамая мощная из них — опция parallel(), она автоматически распределяет данные по параллельным подзадачам. Начиная с 8 версии java можно применять и другие идеи ФП — функции высших порядков, currying, pattern matching и т.д. Некоторые подходы были доступны и раньше, например, использовать хвостовую рекурсию вместо итерации. Но наибольшую практическую пользу можно извлечь из обработки больших коллекций с помощью Stream API. Писать программы в функциональном стиле на чистой java можно, но на практике это пока не оптимально. Для обработки потоков данных больше подходят библиотеки для реактивного программирования и стрим-фреймворки.

Привет! Чтобы писать понятные и полезные посты, мы хотим знать больше о Вас и о том, что Вам интересно. Ответьте, пожалуйста, на 2 вопроса выше☝️ Ещё 4 коротких вопроса в https://forms.gle/Vqdfpjfm59BmPQBa6

Какие темы Вам интересны?
Anonymous voting

Сколько лет Вы пишете на java?
Anonymous voting

5 причин, из-за которых код превращается в легаси. И это вовсе не устаревание технологий и долгий срок проекта. Если для изменения одного поля в API нужно 3 дня разбираться в системе и делать пул-реквест на 75 файлов — это явный признак легаси-системы. Сложно разобраться, сложно изменить и хочется забыть. Главная проблема таких систем — это over-engineering. Почему так происходит? 1️⃣ Предсказание бизнес-требований. Прочитав задачу, программист тут же видит точки расширения и проектирует под это абстракции. Тратит две недели на фундамент, чтобы потом быстро добавить новые форматы здесь, новые типы тут, новые алгоритмы там. Но задача бизнеса — не реализовать всё, что только можно. Задача бизнеса - быстро тестировать идеи и извлекать прибыль из самых перспективных. ✅ Не додумывайте требования бизнеса, просто реализуйте их. 2️⃣ Систематизация бизнес-требований. Если в системе появляется много функций, программисты склонны их группировать и обобщать. Они используют принцип DRY(don't repeat yourself) и создают общие компоненты, которые принимают на вход стратегии обработки и выдают обобщённые типы данных. Чтобы встроить новые бизнес-требования в такие абстракции, абстракции абстрагируются ещё больше. ✅ Не смешивайте функциональность. Если код двух методов похож, но относится к разным бизнес-процессам, оставьте всё как есть. ✅ Используйте «правило трёх»: ▪️ Делая что-то в первый раз, вы просто это делаете. ▪️ Делая что-то аналогичное во второй раз, вы морщитесь от необходимости повторения, но все-таки повторяете то же самое. ▪️ Делая что-то похожее в третий раз, вы начинаете рефакторинг. 3️⃣ Чистота кода. Часто разработчики относятся к задачам как к интеллектуальным головоломкам,у которых есть некоторое «красивое решение»: соответствует принципам SOLID, использует паттерны GoF и распределяет функциональность по слоям – контроллер, сервис, DAO и т.д. Цель понятна — будущая простота изменений. Но эти возможности часто остаются невостребованными. Не каждому микросервису нужна сложная программная архитектура, а даже 4 if-а подряд понять легче, чем иерархию абстрактных классов. 4️⃣ Велосипеды. ORM, маппинг JSON, логгирование, кэширование, сбор и анализ статистики — эти задачи уже давно реализованы в библиотеках или фреймворках. Главная мотивация написания велосипедов в том, что существующие решения кажутся избыточными. Кажется, что свой вариант будет короче и эффективнее. Это маловероятно. Скорее всего Вы потратите много времени на разработку, поддержку и тестирование, а результат будет хуже. ✅ Ищите и используйте готовые решения. 5️⃣ Дедлайны. Если до этого проблемой было чрезмерное усложнение, то перед дедлайном в коде появляются «костыли». Это код, который решает узкую проблему в неподходящем месте системы. Самые ответственные разработчики при этом добавляют комментарий: // todo: refactor Такие артефакты часто остаются в коде, иногда даже дополняются или переносятся в абстракции. ✅ Если Вы знаете, что пишете костыль — не оборачивайте его в абстракции, не приукрашивайте. Пусть он будет максимально понятным и грубым. Идеально — заведите отдельную задачу и сразу же пропишите, как исправить ситуацию. Цель этого поста — не показать, что абстракций делать нельзя, а принципы проектирования нужны только для собеседований. В больших системах over-engineering неизбежен. Однажды она станет тем самым душным легаси, в котором никто не хочет разбираться. В наших силах только замедлить этот процесс. Помните, что главная цель кода — решать бизнес-задачи. А паттерны, принципы и лучшие практики — это только инструменты для достижения этой цели.

Виш-лист разработчика: работа в стартапе и зарплата в долларах. Пост рекламный, но о важных вещах. В карьере разработчика сложны только первые шаги — войти в индустрию и набрать 3-4 года опыта. Спрос на программистов сильно превышает предложение, поэтому в IT большие возможности для самореализации. Можно продвигаться в карьере, увеличивать зарплату или устраивать себе челленджи, например: 🔸️ Пройти путь от джуниора до архитектора за 5 лет. 🔸️ Разобраться в какой-нибудь теме, выступить на конференции и носить футболку с шуткой, которую поймут только 3 человека в мире. 🔸️ Пройти 8 этапов собеседований в Яндексе и отказаться от оффера. Участвовать в молодых проектах — тоже интересная цель. Работа в стартапе совсем не похожа на уютный корпоративный мир. Это: ✅ супер увлечённые люди, ✅ ответственность и дисциплина, ✅ быстро видны результаты работы, ✅ топовые технологии. Конечно, также велика вероятность: ▪️ ненормированного рабочего дня, ▪️ истеричных коллег, ▪️ закрытия проекта через 3 месяца. Многие только после работы в стартапе поняли, что значить РАБОТАТЬ. Не закрывать задачи в джире и лениво отчитываться на стендапах, а решать проблемы здесь и сейчас, адаптироваться к изменениям, быстро внедрять новые технологии. Работа с иностранными заказчиками — тоже специфический опыт. Удалённая работа, высокая зарплата, иностранный язык и иногда совсем другой менталитет. Главная сложность — найти такие вакансии. На HeadHunter они если и появляются, то под названием «ИП Иванов А.И» или «ООО НьюСофт». Чаще всего их там нет🤷‍♂️ @profunctor_jobs — телеграм канал с супергорячими вакансиями и важной информацией — стек, зарплата, локация, график и контакт. Там ищут не только java разработчиков, но это реальный шанс найти интересные предложения. Среди их партнёров: 🤳Snap - компания владеет мессенджером Snapchat, умными очками Spectacles, сервисами Bitmoji и Zenly. 🚗Bolt – транспортная платформа, работающая в 30 странах. 💲Revolut – мультивалютные карты без процентов за конвертацию. Рекомендуем подписаться и следить за вакансиями: @profunctor_jobs

Что есть в твоём виш-листе?
Anonymous voting

Equality: best practices. Или как правильно переопределить метод equals. Полный список в конце поста. Базовая реализация в классе Object проверяет только равенство ссылок - по умолчанию каждый экземпляр класса равен только самому себе. Часто рекомендуют для новых классов переопределять метод equals и проверять равенство по значимым полям. Несмотря на кажущуюся простоту, в реализации equals есть несколько тонких моментов. Кода в этом методе мало, выглядит он просто, а тесты на равенство редко кто пишет. Тем не менее часто встречается ситуация: Странное поведение системы ➡️ неделя дебага по всей бизнес-логике ➡️ ошибка в equals ➡️ гнев и разочарование. Простой способ не ошибиться — не переопределять equals вообще. Иногда это уместно: 1️⃣ Для перечислений (enum) 2️⃣ Когда важны сами экземпляры, а не данные внутри них. Пример - классы Thread, RecursiveTask. 3️⃣ Сравнение объектов вообще не предполагается. Пример - класс Pattern. 4️⃣ В базовом классе уже есть equals и нам подходит эта реализация. 5️⃣ Класс имеет модификатор доступа private или по умолчанию и мы уверены, что метод equals не будет вызван. В остальных случаях его лучше переопределить. Во многих проектах при этом используется аннотация @EqualsAndHashCode библиотеки lombok, ограничения при её использовании мы тоже рассмотрим. Итак, при реализации equals нужно учитывать следующие свойства: 1️⃣ Рефлексивность — экземпляр должен быть равен сам себе. 2️⃣ Консистентность — если экземпляры равны, то без внешних воздействий они должны оставаться равны. ✅ Сравнивать только неизменяемые поля. Чтобы обезопасить себя от проблем с equals по возможности используйте для ключей в Map не классы целиком, а их неизменяемые поля, например, id. Если используете аннотацию @EqualsAndHashCode явно указывайте поля, по которым идёт сравнение. Это поможет избежать ошибок при добавлении в класс изменяемого поля. ✅ @EqualsAndHashCode(of={“x”,“y”}) 3️⃣ Симметрия. Если в системе находятся объекты базового класса и его наследника нужно чётко понимать, как они будут между собой сравниваться. Возьмём класс Точка, где равенство проверяется по координатам. И его наследника — класс ЦветнаяТочка, где сравниваются координаты и цвет. Точка обычная=new Точка(1,1); Точка красная=new ЦветнаяТочка(1,1,RED); Тогда обычная.equals(красная) будет true, а результат красная.equals(обычная) зависит от требований к системе — нужно ли игнорировать цвет в этом случае или нет. 4️⃣ Транзитивность. Это свойство тоже легко нарушить, если мы имеем дело с иерархией: Точка красная=new ЦветнаяТочка(1,1,RED); Точка обычная=new Точка(1,1); Точка синяя=new ЦветнаяТочка(1,1,BLUE); Если мы решили игнорировать цвет при сравнении разных типов, то допустима такая ситуация: красная.equals(обычная) - true обычная.equals(синяя) — true красная.equals(синяя) - true 😥 ✅ Для иерархий классов писать юнит-тесты на симметричность и транзитивность. ✅ Не использовать @EqualsAndHashCode для иерархий классов. 🤔 Если в системе используются объекты базового и произвольного типов рассмотрите вариант замены наследования на композицию. 5️⃣ Сравнение существующего объекта с null должно возвращать false. ✅ Добавить отдельную проверку if(o == null) Итого: 1️⃣ Не переопределяйте equals, если сравнение не предполагается. 2️⃣ Используйте в equals только неизменяемые поля. 3️⃣ Для иерархии классов пишите тесты на симметричность и транзитивность. 4️⃣ Для ключей в Map желательно использовать неизменяемые поля, например, ID. 5️⃣ Не использовать @EqualsAndHashCode для иерархии классов. 6️⃣ При использовании @EqualsAndHashCode явно прописывайте поля. 7️⃣ Кратко проверить два поля на null и равенство можно через Objects.equals(this.a, а) 8️⃣ Проверяйте первыми поля, которые вероятнее всего отличаются. 9️⃣ Не забывайте про hashcode — используйте те же поля, что в методе equals.

Собеседование: план рассказа о прошлом опыте. Техническое собеседование обычно состоит из трёх частей: 1️⃣ Синтаксические и алгоритмические задачки 2️⃣ Рассказ о прошлом опыте 3️⃣ Вопросы на свободную тему Первая часть часто проходит по шаблону вопрос-ответ, её цель - проверить бэкграунд и знание языка. Но интервьюера также интересует опыт кандидата, кругозор и навыки общения. Содержательный рассказ о прошлых проектах - это по сути самопрезентация. Она помогает работодателю понять, подходите Вы для вакансии или нет. Чтобы не тратить время на лишнее, сфокусироваться на главном и ничего не забыть рекомендуем организовать рассказ по следующей схеме: 🔶️Проекты, над которыми Вы работали больше 2 лет назад. 2-3 предложения о теме проекта и основных технологиях. 🔶️ Предпоследний проект — год-полтора назад. Тоже кратко, 4-5 предложений. 🔶️ Последний проект. Это самая актуальная и важная информация, поэтому уделите описанию большую часть времени. Для описания проекта хорошо подходит шаблон «сверху вниз»: 1️⃣ Цель проекта: решаемые бизнес-задачи. 2️⃣ Общая схема: верхнеуровневая архитектура и основные технологии. 3️⃣ Контекст: компонент, который разрабатывала Ваша команда. Покажите на общей схеме, кратко опишите функции и уточните технологии. Расскажите о составе команды, процессе, по которому работали и с кем ещё взаимодействовали. 4️⃣ Ваша деятельность. Эта часть - кульминация, лучше подготовить её заранее. Кратко расскажите о фичах, которыми Вы занимались. Не углубляйтесь в бизнес-описание, лучше подробнее расскажите о результатах, решённых проблемах, какие подходы и инструменты использовали. Если какие-то из них упоминаются в вакансии — сделайте на них особый упор. Чем больше самопрезентация будет опираться на требования вакансии — тем больше шансов получить оффер. Такое описание проектов максимально выделит Ваши навыки и достижения. Интервьюер увидит, что Вы: ▪️понимаете задачи бизнеса ▪️видите общую картину и свой вклад в неё ▪️понимаете процессы внутри команды ▪️умеете решать проблемы ▪️ориентированы на результат Помните, что направление рассказа о предыдущем опыте — не углубляться в технические детали, а показать, что Вы ответственный сотрудник, решаете поставленные задачи и хорошо работаете в команде. Ведь именно этого ждёт будущий работодатель.

Как создать поток: 7 вариантов ответа. Выбирайте любой или комбинируйте несколько, ведь это отличный шанс показать широкий кругозор и перевести разговор в интересную Вам сторону. 1️⃣ Синтаксический ответ — ожидаемый. 🅰️ реализовать интерфейс Runnable или Callable и передать новому объекту Thread: Runnable action = () -> System.out.println("hey"); new Thread(action).start(); 🅱️ расширить класс Thread, переопределить метод run, создать экземпляр этого класса: class MyThread extends Thread {...} new MyThread().start(); 2️⃣ Углублённый ответ. new Thread(...) приведёт к созданию в heap экземпляра класса Thread и сопутствующих объектов —program counter, хранилище thread-local переменных, нескольких стеков, объектов синхронизации и т.д. Вызов метода start() вызывает нативный метод start0(). Через JNI исполнится метод JVM JVM_StartThread, реализованный на C++, который вызывает метод ОС для создания потока. Для Unix это pthread_create. 3️⃣ Практический ответ. Создание потока - ресурсоёмкая операция, поэтому лучше создать пул потоков, которые можно переиспользовать. ExecutorService executor = Executors.newCachedThreadPool(); Runnable action = () -> System.out.println("hey"); executor.submit(action); 4️⃣ Неожиданный ответ. Понятие потока в программировании очень размыто, особенно с учётом русского языка. Thread - структура для параллельного выполнения задач с помощью планировщика и потоков ОС. Поток данных - тоже поток. В случае Stream API это скорее статичная коллекция, но можно рассказать интервьюеру основные методы его создания: list.stream() Stream.of(...) Stream.range(...) Arrays.stream(...) Stream.generate(...) 5️⃣ Хайповый ответ. Раз мы заговорили о потоке как потоке данных, то здесь можно свернуть в тему реактивного программирования. Самые популярные библиотеки для java это RxJava2, Project Reactor и Akka Streams. А также интерфейсы Flow API в java 9 и Reactive Streams. Для примера рассмотрим создание потока в Reactor. Поток из 0 или 1 элемента называется Mono: Mono.just(1) Mono.fromCallable(...) Mono.fromFuture(...) Mono.fromSupplier(...) Поток из N элементов называется Flux: Flux.just(1, 2, 3) Flux.fromIterable(...) Flux.fromStream(...) Flux.range(...) 6️⃣ Big data oriented ответ. В мире big data есть много фреймворков для обработки потоков данных. Apache Spark Streaming, Storm, Flink, Samza, Kafka Streams - если Вы работали с чем-то из этого списка, то обязательно поделитесь с интервьером этим опытом. 7️⃣ Менеджерский ответ. Рассмотрим поток с нетехнической точки зрения. Поток - состояние, когда человек полностью включен в свою деятельность, совершенно сконцентрирован на ней и испытывает удовольствие от работы. Задача руководителя - создать сотрудникам подходящие для этого условия. Можно использовать множество методов: регулярная обратная связь, увеличения прозрачности процессов и т.д. Ответ на банальный вопрос "как создать поток" может различаться в зависимости от опыта и текущей должности. Вопросы на собеседованиях - лишь стартовая точка для обсуждений, не стесняйтесь повернуть разговор на обсуждение Ваших компетенций и сильных сторон.

Сколько времени Вы можете отвечать на вопрос "как создать поток"?
Anonymous voting

IT стендап: неожиданный способ стать сотрудником, за которого бьются компании. У всех есть коллега, который часто предлагает неожиданные решения. Иногда неподходящие, а иногда настолько изящные, что в голову приходит мысль: "Эх, почему не я это придумал". Чтобы стать сотрудником, которым втайне восхищаются коллеги, нужно видеть проблемы и решения, смотреть на привычные вещи под разными углами. Это сложный, но очень ценный навык, который можно развивать. Самый доступный способ — придумывать шутки. Знаете, как пишется материал для КВН, фильмов, мемчиков и стендапов? Редко это лёгкий и остроумный полёт мысли. Часто этот процесс состоит из нескольких шагов: 1️⃣ Погружение в тему и сбор фактов. 2️⃣ Поиск парадоксов и неожиданных сопоставлений. 3️⃣ Поиск выразительной формы для максимального эффекта. Эти действия развивают критическое мышление, умение смотреть на вещи с другого ракурса, генерировать, фильтровать и доносить новые идеи. То, что пригодится и на работе, и в жизни. Первый шаг уже сделан - у вас есть огромный бэкграунд разработки. Настало время идти дальше! Следующий шаг - поиск несоответствий и противоречий. Посмотрите на привычные вещи со стороны. Есть ли в них что-то нелогичное? Необязательно сразу придумывать шутку, главное — заметить что-нибудь интересное. Например, вот нескольких идей, вдохновлённых java 8 и 9: 1️⃣ Stream API: ▫️ожидание: название наводит на мысль о работе с потоками данных, компактном описании бизнес-процессов. ▪️реальность1: обработка статичных коллекций без использования циклов. ▪️реальность2: для дебага и обработки исключений легче переписать обратно на циклы. 2️⃣ Parallel Streams: ▫️ожидание: существенный прирост производительности при добавлении .parallel() ▪️реальность: под большой нагрузкой работает в лучшем случае на 20% быстрее, в худшем - на 15% медленнее. 3️⃣ Выход java 9: ▫️ожидание: тренд на модульную архитектуру, новый взгляд на проектирование приложений. ▪️реальность: разработчики в восторге от List.of() и Map.of(). 4️⃣ Развитие фичи pattern matching: ▫️ожидание: удобный апи для регулярных выражений. ▪️реальность: проверка и приведение типа объекта пишется в одну строку, а не в две. 5️⃣ Поддержка реактивного программирование в java 9: ▫️ожидание: сверхскорость выполнения кода, новый подход к разработке. ▪️реальность: интерфейсы для паттерна Observer. Можете развить и довести эти идеи до конца, а можете придумать свои. Сначала это будет казаться сложным, но это навык, и его можно тренировать. Камон, шутки про java могут быть не только про кофе и многословность😉

Сборщики мусора. Плюсы и минусы G1. Сборщик мусора(garbage collector) - компонент JVM, который размещает объекты в памяти. Выделяет место под новые и определяет те, которые уже не нужны. В java есть 5 типов сборщика мусора - Serial Collector, Parallel Collector, Concurrent Mark Sweep (CMS), Garbage-First (G1) и Z Garbage Collector(ZGC). В java 8 вариантом по умолчанию является Parallel GC, в java 9 это G1. ZGC - самый новый, он появился в java 11. Эффективность GC оценивается по следующим параметрам: ▪️Latency — сколько времени занимает сборка мусора. Измеряется в миллисекундах. ▪️Throughput — как часто она происходит. Пропускная способность считается в процентах времени VM и рассчитывается как обратная величина. Если сборка мусора занимает 5% времени,то throughput равен 95%. ▪️Footprint — сколько ресурсов использует GC. Учитывается количество памяти для корректной работы. Достичь хороших значений во всех трёх показателях невозможно. Для разных GC в приоритете будут разные параметры, но для каждого доступно множество опций для изменений под требования системы. Основной принцип работы сборщика мусора — разделение объектов по поколениям. ▫️Недавно созданные объекты относятся к «молодым». Промежуточные объекты, итераторы, локальные переменные - самые вероятные кандидаты на удаление. На них сфокусирована основная часть внимания GC. Ещё они делятся на 2 подгруппы: только что созданные и выжившие после нескольких сборок мусора. ▫️Если объект пережил много циклов работы GC (по умолчанию 15), то он переходит в «старое» поколение и проверяется реже. Деление на поколения не абстрактное. Если объект переходит в другое поколение, он физически меняет своё место в памяти, и все ссылки на него обновляются. В ранних версиях сборщиков мусора память делилась на 4 региона: 🟥 Eden — здесь создавались новые объекты. 🟧 Survivor – для переживших несколько сборок мусора. 🟪 Tenured – для долгоживущих объектов. 🟦 Permanent – метаинформация JVM о классах, методах и тд. Выглядело всё примерно так: 🟥🟥🟥🟥🟥🟥🟧🟧🟧🟪🟪🟦 В G1 область Permanent удалена, а метаинформация перенесена в отдельную часть памяти под названием Metaspace. Второе изменение — память разделилась на 2000 регионов одного размера, по умолчанию 1МБ. Тип региона может меняться. Для больших объектов регионы объединяются. Стало как-то так: 🟥🟪🟧🟧🟥🟪🟥🟥🟧🟪 Плюсы и минусы G1: ✅ Выборочная обработка группы регионов – получаем высокий latency. ✅ Предсказуемое время обработки. ✅ Сборка мусора в основном выполняется параллельно с работой приложения. ✅ Нет проблем с фрагментацией. ➖ Затраты на поддержку такой системы чуть снижают throughput. Целевое значение пропускной способности для G1 - 90%. Для Parallel GC это значение равно 99%. ➖ Плохо работает с heap меньше 6Гб. Чтобы проанализировать и оптимизировать работу G1, в первую очередь нужно включить логгирование, а уже затем экспериментировать с флажками JVM. -Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime Но вообще G1 адаптируется к нагрузке и прекрасно работает со значениями по умолчанию.