Получи случайную криптовалюту за регистрацию!

Java: fill the gaps

Логотип телеграм канала @java_fillthegaps — Java: fill the gaps J
Логотип телеграм канала @java_fillthegaps — Java: fill the gaps
Адрес канала: @java_fillthegaps
Категории: Технологии
Язык: Русский
Количество подписчиков: 10.33K
Описание канала:

Привет! Меня зовут Диана, и я занимаюсь java разработкой с 2013г.
Делюсь опытом/знаниями по темам:
- Java Core
- Вопросы с собеседований
- Best practices
Комплименты, вопросы, предложения: @utki_letyat

Рейтинги и Отзывы

4.50

2 отзыва

Оценить канал java_fillthegaps и оставить отзыв — могут только зарегестрированные пользователи. Все отзывы проходят модерацию.

5 звезд

1

4 звезд

1

3 звезд

0

2 звезд

0

1 звезд

0


Последние сообщения 2

2022-07-19 09:20:00 Невозможно не рассказать — сейчас на Хабре идёт сезон джавы.

Все статьи под этим тэгом дополнительно продвигаются хабром. Если есть чем поделиться, то сейчас идеальный момент!

Для лучших статей заявлены призы, так что авторы стараются — есть много симпатичных статей с картинками и подробными примерами. Качество материала разное. Есть милая статья об AssertJ, некомпетентная про виртуальные потоки и обстоятельный справочник по Spring. Вот список статей, может найдёте что-то интересное для себя.

Теперь обратно к этому каналу. На этой неделе расскажу принцип работы двух популярных брокеров сообщений:

Сегодня про RabbitMQ
В четверг про Kafka
4.0K views06:20
Открыть/Комментировать
2022-06-30 09:00:02 Structured concurrency

В java 19 войдёт новый JEP в стадии "инкубатор" — Structured concurrency. В этом посте расскажу, зачем он нужен и какую проблему решает.

Многопоточка многих пугает своей сложностью. Но на самом деле java — очень дружелюбный язык, и новый JEP — отличный тому пример.

Как выполнить большую задачу быстрее? Разбить на подзадачи, отправить в экзекьютор и объединить результаты:

Future f1=executor.submit(…);
Future f2=executor.submit(…);

return f1.get() + f2.get();

Что будет, если в задаче для f1 выбросится исключение?
Мы узнаем об этом только при вызове f1.get()
Задача в f2 продолжит работу, хотя это бессмысленно. В лучшем случае она просто потратит процессорное время

Так как подзадачи логически не связаны между собой, программист должен добавить прерывания и механизмы отслеживания ошибок.

Новый JEP берёт часть забот на себя:
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future f1=scope.fork(…);
Future f2=scope.fork(…);

scope.join();
scope.throwIfFailed();

return f1.resultNow()+f2.resultNow();
}

Что происходит:

scope.fork — задачи запускаются в едином логическом блоке
scope.join — ждём завершения подзадач
scope.throwIfFailed — пробрасываем исключение, если оно возникло в одной из подзадач. Другим методом можно получить экземпляр исключения и обработать его сразу
Забираем результаты через resultNow и объединяем

С первого взгляда всё то же самое. Но самое интересное происходит в первой строке, где определяются правила взаимодействия подзадач:

ShutdownOnFailure — если хотя бы одна подзадача выбросит исключение, остальные будут прерваны. Обработку прерывания всё ещё пишет разработчик, но java берёт на себя всю работу по отслеживанию и обновлению статусов

ShutdownOnSuccess — когда хотя бы одна задача завершится, остальные прерываются

Бонус — JVM в курсе связей между задачами, поэтому в тред дампе подзадачи будут в древовидной структуре.

Чем ShutdownOnSuccess отличается от методов anyOf в экзекьюторах и CompletableFuture?

В текущих вариантах при ошибке другие задачи не прерываются, в лучшем случае задачи удаляются из очереди

Что классного в этом JEP?

Что по сути эта фича необязательна. Хоть кто-нибудь жаловался, что подзадачи в тред дампе не связаны? Что неудобно следить за исключениями в подзадачах?

Нет, никто не жаловался. Но разработчики java изучают сценарии использования языка и стараются облегчить жизнь пользователям
7.0K viewsedited  06:00
Открыть/Комментировать
2022-06-28 09:00:07 Пет-проекты в резюме: основные ошибки

Раньше пет-проект в резюме джуниора был редким явлением и сильно выделял кандидата среди других. Сейчас ссылки на гитхаб встречаются чаще, да и джуниоров стало больше. В этом посте кратко расскажу о 6 ошибках, которые портят впечатление и снижают вероятность приглашения на собес.

Нерабочий проект

Видно, что код не работает и ни разу не запускался, много пустых файлов и TODO комментариев

Как лучше: выкладывать готовые фичи, задачи в разработке описать в README

Устаревшие технологии и подходы

XML конфигурация в Spring, сервлеты, JSP, Spring 3 и другие старые версии популярных библиотек и фреймворков

Как лучше: учиться по туториалам не старше 5 лет

Слишком сложный код

Интерфейс и абстрактный класс для каждой сущности
Классы с одним полем и геттерами-сеттерами
Функциональные интерфейсы из функциональных интерфейсов

Тяжело читаемый код

Непонятные имена методов, классов и переменных
Методы с сайд-эффектами, там где их быть не должно
Длинные методы
DRY любой ценой
Методы возвращают комбинации из Map, List, Pair и примитивов
Процедуры вместо функций

Что я имею в виду:
filter(List input, List output);
List filtered = filter(input);

Нет бизнес-логики

Вариант 1: простейший CRUD для двух сущностей

Как лучше: если не хватает идей, возьмите любое приложение или сайт и реализуйте 5 интересных фич оттуда

Вариант 2: 300 классов с простейшими функциями. Яркий пример — игры со множеством персонажей и предметов. Непонятно, куда смотреть и что происходит

Как лучше: сфокусировать бизнес-логику в нескольких классах, разбить код на пакеты, написать README

Неоднородный код

Когда части проекта копируются из разных источников как есть. Смешивается xml, yaml и Java-based конфигурация, документированные и стильные блоки кода находятся рядом с неформатированным безумием

Как лучше: не слепо копировать код, а понять решение и адаптировать под проект

Бонусный пункт: не ориентироваться в проекте

Когда на этапе собеседования человек отвечает на вопросы по собственному коду вот так:

Я забыл, зачем это
Тут надо переделать
Сюда не смотрите
Не знаю, зачем, но без этого не работает

Как лучше: пусть в пет-проджекте будут не все технологии, но вы понимаете, что происходит, готовы обсудить решения и ответить на дополнительные вопросы.
5.2K views06:00
Открыть/Комментировать
2022-06-22 09:30:22 Что происходит на курсе

Начну с горячей новости Теперь можно оплатить курс НЕроссийскими картами! Если это ваш случай, напишите мне , расскажу как это сделать с комиссией всего 4%.

Теперь к теме поста — расскажу про материалы на курсе.

Теория

Эта часть не сильно меняется от потока к потоку — лекции занимают 10-20 минут и максимально насыщены информацией.

Периодически их перезаписываю. JEP про виртуальные потоки вышел совсем недавно — а лекция уже обновилась

После лекции идут тесты на теорию и вопросы с собеседований. Не самая интересная часть, но необходимая.

Практика

Больших проектов на курсе нет. Тем и ситуаций много, а практика многопоточки в одном проекте ограничена. Это всё равно, что в одном сервисе применить 23 GoF паттерна — можно, но далеко от реальности.

Задания небольшие и сфокусированные:

Анализ сниппетов

Любимые задания учеников Найти ошибки, разобрать приёмчики, понять, что хотел сказать автор, предложить более изящное решение. Большинство сниппетов из реальных проектов!

Рефакторинг и написание кода

Лабораторные работы — новый тип заданий в 5 потоке!

Приведу пример, как это выглядит и зачем нужно:

На практике много ошибок связано с неудачным подбором параметров экзекьютора.

Что было раньше: в лекции про экзекьюторы рассказывала возможные формулы и подходы, были задания посчитать оптимальное количество потоков при разных условиях

Проблема: тема сдана, но пару недель спустя в других заданиях ошибки повторяются

Что сделала: добавила задание на исследование производительности в зависимости от параметров экзекьютора и вида нагрузки. Ученику даётся готовый код и нагрузочный тест, остаётся экспериментировать с параметрами и нагрузкой. Увидеть своими глазами, как параметры влияют на результат — бесценно

И таких примеров много. Всё понятно, последовательно и наглядно. Присоединяйтесь!

https://fillthegaps.ru/mt5
1.8K views06:30
Открыть/Комментировать
2022-06-20 09:00:07 Анонс курса по многопоточке

Привет! Сегодня открывается набор на курс по многопоточному программированию.

Кто давно ждал и уже готов → вам сюда

Что будет?

Курс строится вокруг java.util.concurrent — боевой лошадки каждого нагруженного сервиса. В деталях изучим все классы, концепты и практическое применение. Разберём огромное количество кейсов, лучших практик и возможных ошибок. Немного затронем смежные темы: тестирование, виртуальные потоки и реактивное программирование.

Уровень: middle/senior
Старт: 11 июля
Длительность: 8 недель

Полная программа, отзывы и запись тут: http://fillthegaps.ru/mt5

Зачем идти?

Закрыть пробелы в базе. java.util.concurrent — важная часть java core
Работать на любых проектах. Многопоточка есть не только в хайлоад сервисах, а вообще везде, хоть и прячется под слоем абстракций
Выбирать оптимальное решение для многопоточных задач, а не первое работающее со StackOverflow
Круто выглядеть на собеседовании. Кандидат, который внятно говорит про модель памяти и приводит жизненные примеры, сразу попадает в категорию "интересный"

Сколько стоит?

До 25 июня действует скидос:
Тариф без обратной связи: 29900 23900
Тариф с обратной связью: 59900 44900

Курс можно оплатить за счёт компании! Пусть ваши коллеги напишут на diana@fillthegaps.ru

Аналогов у курса нет. С каждым потоком программа становится лучше, задания интереснее, а учёба приятнее. Обычно процесс улучшений остаётся за кадром, но на этой неделе расскажу обо всём подробно.

Если хотите разобраться с многопоточкой, и вам близок мой стиль изложения — записывайтесь, будет очень полезно:
http://fillthegaps.ru/mt5
1.8K views06:00
Открыть/Комментировать
2022-06-17 09:00:07 Переключение между задачами

Иногда во время работы над одной задачей нужно переключиться на другую: поправить пул реквест или сделать хотфикс. Если текущие изменения не готовы для полноценного коммита, можно использовать stash или shelve.

Stash

Изменения сохранятся в локальном git репозитории, а текущая ветка почистится. Можно спокойно переключаться на другую задачу.

git stash save "stash name"
В IDEA: VCS → Git → Stash Changes...

Вернуть изменения на место:
git stash apply "stash name"
и оставить stash в локальном репозитории
git stash pop "stash name"
и удалить стэш
В IDEA: VCS → Git → Unstash Changes...

Что важно:
Сохраняются ВСЕ текущие изменения в ветке
Обратно применяются ВСЕ изменения в стэше
Изменения хранятся в локальном git репозитории

Shelve

Удобная фича IDEA для сохранения части изменений:

VCS → Shelve Changes...
Галочками отмечаем, что сохранить.

Чтобы вернуть обратно:
Вкладка Git (Alt + 9 или найдите внизу) → Shelve
Отмечайте, какие изменения применить к коду

Можно выбрать, что сохранять
Можно указать, что восстановить
Изменения хранятся в локальном IDEA проекте
1.8K views06:00
Открыть/Комментировать
2022-06-14 09:00:07 Как освоить многопоточное программирование

Как вы знаете, я периодически провожу курс по многопоточке. Он классный и сильно упрощает освоение темы. Но не всем подходит такой формат, поэтому поделюсь планом, как разобраться в теме самостоятельно.

Многопоточность — сложная часть java core, поэтому разработчика от неё часто ограждают. Большинство проектов используют модель thread-per-request: каждый запрос изолирован, и взаимодействия потоков как будто нет.

Во многих проектах знания многопоточки не понадобятся, особенно если вы джуниор или мидл. Но чем выше нагрузка, тем сложнее поддерживать изоляцию. Так что рекомендую уделить этой теме внимание.

Теория

Шаг 1: любой курс на ютубе или юдеми для быстрого обзора

Шаг 2: книга Java Concurrency in Practice + документация к каждому классу java.util.concurrent

В книге отлично описаны основы и возможные проблемы многопоточки. Многие практические решения устарели, поэтому ищите в JDK альтернативы.

Шаг 3: видяшки Романа Елизарова и Алексея Шипилёва

Дают хороший ответ на вопросы "почему" и "зачем". Смотреть только после предыдущего шага, иначе можно утонуть в деталях и не понять главного

Шаг 4 (опциональный): прочитать The Art of Multiprocessor Programming

Не про джаву, но теоретические аспекты многопоточности раскрыты на тысячу процентов.

Почему так много теории?

Потому что между железом, внутрянкой JVM и архитектурой сервера очень тесная связь. Без этого фундамента получаются такие ситуации:
Локально всё работает, тесты проходят, а на продакшене непонятные ошибки
Одна многопоточная фича работает, но почему-то отваливается другая
Вроде ничего не сделал, а метрики стали в два раза хуже

Практика

Идеальный вариант — делать многопоточные задачки под присмотром опытных коллег. Если такой возможности пока нет:

Поискать куски многопоточки в текущем проекте. Даже если их мало, разберите от и до — что, зачем, почему такие параметры, как можно по-другому
Изучить код опенсорсных проектов, которые точно содержат многопоточку — Kafka, Hadoop, Tinkoff invest API, etc

С этим багажом можно спокойно идти на собеседование в классный проект и нарабатывать навыки + периодически повторять материалы из шага 2
1.8K views06:00
Открыть/Комментировать
2022-06-03 09:00:11Как сравнить строки без учёта регистра

В этом посте расскажу, как решить задачу из предыдущего поста и сделать метод быстрее, чем в JDK.

Напомню задачу: сравнить две строки без учёта регистра и оценить производительность в разных ситуациях.

Шаг 1. Смотрим подходящие методы в классе String

s1.toLowerCase().equals(s2.toLowerCase())
s1.equalsIgnoreCase(s2)
s1.compareToIgnoreCase(s2) != 0
s1.regionMatches(true, 0, s2, 0, s2.length())

Шаг 2. Предположим возможные ситуации

Строки могут сильно и слабо отличаться по регистру.

Скорее всего, алгоритмы для пустых, коротких и длинных строк одни и те же, так что не будем различать эти случаи.

Шаг 3. Углубляемся в реализацию

toLowerCase + equals

Для каждой строки создаёт копию в нижнем регистре. Затем включается обычный equals:
Сравнивает длины строк. Если не равны, сразу возвращается false
Сравнивает по одному символу, пока не дойдёт до конца строки или пока символы не будут разными

В начале целиком обходим s1 и s2, чтобы создать копии в нижнем регистре. Когда длины строк отличаются (что можно узнать сразу), эта работа бесполезна
Если строки мало отличаются по регистру, то приведение всех символов к одному регистру будет лишним

compareToIgnoreCase cравнивает элементы по порядку. Если символы не равны — вызывает апперкейс и сравнивает ещё раз.

Uppercase происходит только при необходимости. Если разница в регистрах небольшая (s1=java, s2=Java), то этот подход будет быстрее
Цель метода — сравнить строки, поэтому нет быстрой проверки длины

regionMatches берёт символы из строк s1 и s2, сразу делает uppercase и сравнивает

Если строки по регистрам сильно отличаются, предварительный апперкейс ускорит проверку
Метод работает с подстроками произвольной длины, поэтому нет быстрой проверки длин

equalsIgnoreCase сравнивает длины строк, потом вызывает regionMatches

Итог

Если строки разной длины, то однозначно побеждает equalsIgnoreCase
Если длины одинаковы и
— регистры не сильно отличаются, то побеждает compareToIgnoreCase
— нужно много преобразований — regionMatches

equalsIgnoreCase для каждого символа делается апперкейс. Если строки по регистрам слабо отличаются, то это явно лишнее. Для таких случаев подойдёт кастомный метод:

if (s1.length() != s2.length()) {
return false;
}
return s1.compareToIgnoreCase(s2) != 0;

Лучшее из двух миров — быстрая проверка по длине и нет лишних апперкейсов.

Ниже — бенчмарки всех вариантов. Результаты на разных железках могут отличаться!
317 views06:00
Открыть/Комментировать
2022-06-01 09:00:10 Задачи для собеседований

Как выглядят собеседования в прекрасной России будущего:
нет вопросов на внимательность
нет вопросов о PhantomReference и методах сервлетов
алгоритмы спрашивают, только если они используются на проекте
одна сессия не превышает часа, в сумме процесс найма длится не больше трёх часов
к собеседованиям вообще не нужно готовиться

В этом посте поделюсь парой идей, как приблизить это светлое время.

Цель собеседования — найти сообразительного и внимательного человека. Он хорошо знает язык программирования и технологии, понятно излагает мысли и пишет симпатичный код.

Теоретические вопросы ок, но полезно посмотреть, как человек работает с кодом. Тестовые задания ок, но занимают много времени, поэтому сеньоры и мидлы часто отказываются их делать.

Посмотреть на человека "в деле" можно проще — обсудить уже готовый код и на его основе решить небольшую задачку. Удивительно, но даже задания меньше 20 строк люди делают по-разному.

Что можно обсудить:

Пет-проджект или предыдущие наработки кандидата

Если проект большой и сложный, попросите показать два самых интересных класса.

Плюс: вы видите код первый раз, можно лучше оценить soft skills кандидата и его подход к написанию кода
Минус: пет-проект может быть далёк от задач и стека целевого проекта

Часть текущего проекта (куда ищем кандидата)

Показать упрощённую версию или обсудить код ключевых классов. Транзакции, стратегии работы с кэшем, работа с БД, многопоточка и другие важные темы на конкретных примерах

Найдите в истории проекта несложную задачку и обсудите путь решения. Помните, что человек видит код первый раз и волнуется. Будьте добры к кандидату:)

Код опенсорсных проектов или произвольные сниппеты кода

Прикладные алгоритмические задачки

Прекрасно подойдут, если в проекте неплохая нагрузка и много задач на оптимизацию.

Пример задания: сравнить две строки без учёта регистра:
предложить несколько вариантов (минимум 3)
оценить, когда какой вариант быстрее

Задача интересная, основана на реальных событиях, а для решения нужен только исходный код String.

Ответ выложу в следующем посте!
2.0K views06:00
Открыть/Комментировать
2022-05-27 09:06:30 Где пригодится интерфейс Supplier

Функциональные интерфейсы появились в java 8 и помогают писать код в функциональном стиле:

Function преобразует элемент в новое значение:
stream().map(x → x.toString())

Через Predicate передаётся условие фильтрации:
stream.filter(x → x > 5)

Consumer используется в Stream API и библиотечных классах как терминальная операция:
list.forEach(e → System.out::println)

Supplier ничего не принимает, но возвращает значение:
Stream.generate(() -> LocalTime.now())

Function, Predicate и Concumer активно используются за пределами Stream API, а вот что делать с Supplier — не всем понятно. Зачем определять метод
void m(Supplier list)
вместо void m(List list) ?

Популярные версии:
Кастомизация экземпляра. Передаём другой Supplier — возвращается другой экземпляр.

Для этой задачи проще указать интерфейс в параметрах

Реализация фабрики

Вариант из Effective Java, item 5. Источник авторитетный, но исходная цель Supplier здесь ускользает.

Во-первых, зачем передавать в параметры метода фабрику? Почему бы не создать экземпляр ранее и передать его?

Во-вторых, цель фабричного метода — упростить создание сложных объектов или отдавать разные объекты в зависимости от параметров. Supplier не содержит параметров и слабо подходит под эту задачу.

Цель Supplier — ленивая инициализация. Объект создаётся, когда он нужен, либо не создаётся вообще.

Игрушечный пример:

public Connection init(Supplier connSupplier) {
// взять коннекшн из пула
return connSupplier.get();
}

Если выполнение не дойдёт до connSupplier, новый объект создан не будет. В варианте

public Connection init(Connection conn)

для вызова метода нужно передать УЖЕ готовый экземпляр.

Другой пример — метод Optional orElseGet(Supplier supplier). Новый объект создаётся только, если Optional пуст.

Supplier участвует в сдвиге java в сторону функциональности. Function, Predicate и Concumer организуют функции высшего порядка, а Supplier — ленивые вычисления. Полезно в двух случаях:

Когда объект может не пригодиться внутри метода
Инициализировать объект нужно в момент вызова, не раньше. Например, у объекта в конструкторе есть LocalTime.now()
1.8K views06:06
Открыть/Комментировать