Notes about Java 🌴
197 subscribers
41 photos
1 video
3 files
76 links
vk.com/notes_about_java
Научим программировать с нуля!
1. Видео на практике в коде
2. Краткие по времени
3. Очередной урок только на пройденном
4. Понятные аналогии
5. Можно скачать код занятий
@max_urusoff
Download Telegram
#builder #lombok

Как реализовать builder паттерн если аннотация вешается на конструктор родительского класса и на конструктор наследника?

На скриншоте явно определена проблема - компилятор ругается на метод builder по возвращаемому типу.

Решение заключается в том, что в аннотацию надо добавить свое имя билдер метода для наследника:
@Builder(builderMethodName = "sunnyBuilder")

Еще один пример для решения этой проблемы можно прочитать по ссылке в пункте "2.3. Сосуществование нескольких Builders".
https://javascopes.com/lombok-builder-inheritance-bce31ecd/
👍1
#mutable #immutable #cuncurrency

https://youtu.be/f8nEQ5zDsOQ

На мой взгляд настоящее понимание мутабельности, а особенно в контексте многопоточки - это фундаментальная тема.

В этом видео автор кратко раскрывает вопрос почему иммутабельность - это выгодно!
🤔1
#threadlocal

Столкнулся с проблемой - завел ThreadLocal поле, выполнил .set(), а это поле хоть ты тресни, при запуска сервиса в многопоточном режиме - null и все!

Оказывается, чтобы ThreadLocal поле получило значение внутри параллельной зоны кода - нужно задавать через .set() внутри этой многопоточной зоны кода (в рамках ThreadPool, в котором поле должно иметь определенное состояние).

А от того, что до попадания в параллельную зону делал .set() - ThreadLocal полю на это "фиолетово", оно как было "null" (по инициализации при создании класса), так "null" и зашло в зону работы ThreadPool.

Хоть 100 раз делай .set() до многопоточного режима - ThreadLocal поле окажется в параллельной зоне в таком состоянии, в которым оно было создано.

Мораль басни такова - задать значение ThreadLocal для работы в параллельности можно 2 вариантами:
1) При создании экземпляра класса.
2) С помощью .set() но только внутри многопоточной зоны.

Классные примеры "thread-safety":
https://javascopes.com/java-thread-safety-11db95ab/
🔥4👍1
#atomicreference

Почему когда пишешь Stream то IDEA предлагает конвертацию в AtomicReference?
Вообще для чего нужен этот тип полей?

Атомики - это классы, которые выполняют операции изменения своего значения атомарно, т.о. они поддерживают lock-free thread-safe использование переменных. Достигается это с помощью алгоритма compare-and-swap (CAS) и работает быстрее, чем аналогичные реализации с блокировками. На уровне инструкций большинства процессоров имеется поддержка CAS.

Например, на скриншоте метод addMissedColToDf может работать в многопоточке и потоки сильно захотят зайти в переменную resultDf и добавить колонку к набору данных, но она (resultDf) даст поработать с ней только по очереди во избежание разбитого состояния каждым из потоков одновременно!

То есть операция либо выполняется полностью либо это поле посылает java действие лесом и не дает ничего сделать.

Классное описание атомиков:
https://github.com/jmorozov/awesome-java-backend-interview-rus/blob/main/java/concurrency.md#как-работают-атомики
👏2
#idea #replace #refact

Сегодня делал много замен в коде ввиду разделения классов модуля на несколько модулей по логическому функционалу.

Стимулирующая к работе картина, когда ссылки на объекты краснеют, проект не собирается...

И тут на помощью приходит IDEA!

Горячее сочетание клавиш "Ctrl+Shift+R" и меню замены спасает это покраснение.
Особенно мне понравилась опция замены на базе выделенной зоны. Для этого в "Scope" надо выбрать "Selection".

Подробнее о замене есть в статье на сайте JetBrains: https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html#replace_search_string_in_project
👍3
#forkjoinpool

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

Надо сказать, что справляется со своей задачей хорошо. Были сделаны сравнения с классическим fixedThreadPool. В результате тестов под настоящей нагрузкой forkjoin подход первым прорвал линию фронта и отработал без ошибок.

В чем сила??
В нем воровская технология отбирания задач у соседа!
Простыми словами можно сказать, что ядра-потоки помогают друг другу в беде, если кого-то из них заваливают.
На самом деле в литературе эта технология так и называется "work stealing".

Классная статья на тему:
https://www.google.com/amp/s/nuancesprog.ru/p/11996/%3famp
🤔2
#functionalinterface

Допустим надо получить длину строки.
Пишем в коментах - какой вариант вам нравиться и почему?
1. s -> s.length()
2. String::length

Мне нравится, когда в коде используется method reference с двойным двоеточием :: лаконично и красиво. О рекомендации по method reference кстати пишет и Джошуа Блох в книге "Effective Java".

Есть такой вид интерфейсов - "функциональный интерфейс" – содержит только 1 абстрактный метод, и позволяют получить возможность делать method reference :: и пользоваться лямбда выражениями ->.

На такие интерфейсы обычно вешается аннотация @FunctionalInterface - обеспечивает наличие только одного абстрактного метода.
ВАЖНО - default и static методы не в счёт.

https://javarush.ru/groups/posts/592-java-functional-interfaces
👍2
#spring #enabletransactionmanagement #transaction

С версии 3.1 Spring ввел аннотацию @EnableTransactionManagement, которая используется с аннотацией @Configuration над конфигурационными классами и включает поддержку бесшовной транзакций через аннотацию @Transactional.

И че за аннотация @Transactional и почему бесшовные??
Метод помечен как @Transactional - это означает откат всех записей, если любая из операций вставки в этом методе завершится неудачей, а также Spring бросит оригинальное исключение.

ВАЖНО: если в методе с аннотацией @Transactional будут действия с БД в виде цикла и будет ошибка хотя бы в одном - то ни один элемент из списка не запишется.

Пример записи в виде цикла:
@Transactional
public void book(String... persons) {
for (String person : persons) {
log.info("Booking " + person + " in a seat...");
jdbcTemplate.update("insert into BOOKINGS(FIRST_NAME) values (?)", person);
}
};

https://spring-projects.ru/guides/managing-transactions/
👍3
#springscopes

Например, с помощью аннотаций
@Component
@Scope("prototype")
над классом, мы укажем, что бин создается каждый раз, когда бин необходим в качестве зависимости.

Ниже список областей видимостей, описанных в документации на момент написания:

singleton - По умолчанию. Создаётся единственный экземпляр. Для бинов без состояния(stateless).

prototype - создается каждый раз, когда бин необходим в качестве зависимости. Для бинов с сохранением состояния(stateful).

request - ограничен единственным HTTP запросом. (web компонент)

session - жизненный цикл экземпляра ограничен в пределах одной и той же HTTP сессии. (web-компонент)

global session - жизненный цикл экземпляра ограничен в пределах глобальной HTTP сессии. (web компонент)

application - жизненный цикл экземпляра ограничен в пределах ServletContext. (web компонент)

Пример:

@Component
@Scope("prototype")
public class GreetingServiceImpl implements GreetingService {
//вкусная начинка
}

https://spring-projects.ru/guides/lessons/lesson-2/
👍3
#springprofiles

Профиль в спринге - это именованная группа определений бинов.

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

Чтобы каждый раз не пересобирать приложение с разными конфигурациями, изпользуем профили:

@Configuration
public class AppConfig {

@Bean
@Profile("dev")
public DataSource devDataSource() {
// test options
}

@Bean
@Profile("production")
public DataSource productionDataSource() throws Exception {
// real options
}
}

Важно!
Если класс конфигурации аннатирован @Profile({"p1", "p2"}), то она будет действовать, если профили "р1" и/или "р2" будут активны. При @Profile({"p1", "!p2"}) конфигурация действует, если профиль "р1" активен или профиль "р2" не активен.

https://spring-projects.ru/guides/lessons/lesson-2/
#nonnull #npe

Чтобы сделать поле или параметр не null, добавь аннотацию @NonNull.
И не парься.
Ломбок сам сгенерит проверку на NullPointerException.

Разбор аннотации здесь:
https://projectlombok.org/features/NonNull
👍4
#мусор #unused

Если код в проекте не используется, то нечего его хранить. И поддерживать пакеты понятнее, если класс стоит на месте, то значит работает.
При необходимости через Git можно восстановить нужный класс из истории репозитория.
В IDEA есть инструменты инспекции и анализа кода.

Можно пойти таким путем:
Code > Analyze Code > Run Inspection by Name > Unused declaration.

https://intellij-support.jetbrains.com/hc/en-us/community/posts/360010821479-How-to-use-IntelliJ-IDEA-to-find-all-unused-code-
👍2
#todo

Пиши //TODO комментарии прям на месте "не отходя от кассы" пока помнишь что хотел сделать с классом или методом.
В IDEA есть отдельная вкладка снизу для отображения TODO и этим очень удобно пользоваться.

В отличии от записок из блокнотов, TODO не надо искать по проекту как иголку в стоге сена, он уже написан в том месте, где требуется лечение.
👍3🏆3
#forkjointask #completablefuture

Чтобы запустить ForkJoinTask в ForkJoinPool со своими настройками, мне удалось найти такое решение:

CompletableFuture<?> cf = CompletableFuture.runAsync(forJoinTask::invoke, customForkJoinPool);

В такой конструкции получаем классные плюсы:
1. Результаты объеденных CompletableFuture с отловом InterruptedException и ExecutionException исключений через CompletableFuture.allOf(cf1, cf2).get(), чего нет при вызовах через ForkJoinPool::invokeAll и ForkJoinTask::invokeAll.
2. Возможность управления поведением каждого из потоков с помощью богатого контракта CompletableFuture.
3. Использование настроек своего customForkJoinPool. Я как минимум делаю спец. имена ForkJoinWorkerThread потоков для каждого из сервисов в проекте.

Пример создания сustomForkJoinPool:

protected СustomForkJoinPool(int logicTasksCount) {
int availableProcessors = Runtime.getRuntime().availableProcessors();
ForkJoinPool.ForkJoinWorkerThreadFactory workerFactory = this::initWorkerFactory;
if (logicTasksCount < availableProcessors) {
this.threadPool = new ForkJoinPool(logicTasksCount, workerFactory, null, false);
} else {
this.threadPool = new ForkJoinPool(availableProcessors, workerFactory, null, false);
}
log.info("Thread pool parallelism level - {}.", threadPool.getParallelism());
}

private ForkJoinWorkerThread initWorkerFactory(ForkJoinPool pool) {
ForkJoinWorkerThread thread = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
thread.setName("MyService-" + thread.getPoolIndex());
return thread;
}

https://www.baeldung.com/java-completablefuture
https://www.baeldung.com/java-work-stealing
🤔1
#jokerconf

Скоро состоится одна из самых крупных площадок по Java разработке!
Вот список докладов по разделам:
https://jokerconf.com/talks/

Есть возможность попасть на кусочек пирога и бесплатно, подробнее здесь:
https://jokerconf.com/registration/personal/
#immutablemap

ImmutableMap на самом деле полезная вещь и порой недооценена там где она должна быть.
Уверен, что значения в мапе будут меняться? На самом деле?

Может достаточно сделать вот так:
ImmutableMap<String, String> immutableMap = ImmutableMap.<String, String>builder()
.putAll(someMutableMap)
.put("Costa Rica", "North America")
.build();

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

Подробнее здесь:
https://www.baeldung.com/java-immutable-maps
👍5
#singular

Удобно пользоваться аннотацией @Singular от Lombok в билдерах @Builder.
Аннотация автоматически генерирует возможность подавать элементы коллекции в билдере в виде:
.table(sourceTable)
.table(targetTable)

Вместо оборачивания всех подаваемых полей через конструкцию из древних веков - Arrays.asList(sourceTable, targetTable).

https://www.baeldung.com/lombok-builder-singular
🤓1
#lombokvar

Когда ты знаешь контекст и тебе быстро нужно определённое поле под рукой, то Lombok var - то что надо.
Достаточно написать вот так как на картинке (указано стрелкой) и стринги готовы к  работе.

ВАЖНО!
С этими var надо быть внимательным:
- при множестве таких полей не перепутать при работе
- не стоит давать малопонятные имена var полям
- это lazy тип, который получает себя от начинки.

https://www.baeldung.com/java-lombok-val-var
👌1
#cachedthreadpool

Важно контролировать кол-во потоков (thread) и задач (task) в работающем пуле (thread pool), в противном случае многопоточка может только навредить работе приложения.
Это связано с тем, что потоки и задачи в очереди кушают ресурсы (память и процессор).
Особенно это касается Cached Thread Pool.
В этом типе пула очередь не может хранить задачи и создаёт новый поток если все заняты.
Так же этот тип пула не рекомендуется для I/O задач ВВОДА-ВЫВОДА.
Он подходит для ограниченного кол-ва задач и маленьких по времени выполнения.

👉 Почитать здесь:
https://www.baeldung.com/java-executors-cached-fixed-threadpool

https://javarush.com/quests/lectures/jru.module2.lecture23
👍1