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
#мусор #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
#agile

Работаю в аджайле с 2017 года.
И хочется здесь отметить пару моментов из реального опыта глазами разработчика.
Возможно пригодится.

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

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

Сформировалось мнение, что аджайл возможно будет полезен для сайта типа wildberries (frontend часть) потому, что:
1. Сайт уже кто-то нормально сделал и он работал ещё до мыслей об аджайле.
2. Пользователи (бизнес) могут конструктивно оценить фичи уже работающего сайта и их стоит учитывать в технической реализации.

Во всех остальных кейсах аджайл будет провоцировать на быстрый поиск ПОЛУ-СЫРОГО или пилотного функционала (возможно и с аутсорс сострудниками), его быструю адаптацию и доработку.

А настоящему Java разработчику важно:
- интересный стек с задачами
- участие с тем, чтобы то что написано проработало адекватное время и не было выброшено в связи со стихийными изменениями архитектуры
- хорошие ТЗ и ответственность сотрудников за свои области

Так что фокусируемся на качестве кода проекта и интересных темах!

Статья для почитать ниже
https://habr.com/ru/post/580326/
👍2
#transient

Когда класс участвует в сериализации, но есть поля, которые не нужны после десериализации, то вешай модификатор TRANSIENT на поле.
Это позволит:
- не упасть лицом в грязь, записав пароль пользователей в класс
- ускорить выполнение, освободив сериализацию от мусора.

Бывает так, что сериализация достаётся по наследству от родительского класса.
Как раз такой пример представлен на скриншоте. Но мне в данном случае не надо, чтобы мои поля участвовали в сериализации. Более того, если убрать TRANSIENT, то на класс ругается система проверки качества кода SonarQube.

https://javarush.com/groups/posts/2898-chto-skrihvaet-modifikator-transient-v-java
🤔1
#desing #interface

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

То есть в какой-то момент нужна новая реализация на интерфейсе, а вместо этого в проекте абстрактный класс с уже прописанной в нём реализацией.

https://stackoverflow.com/questions/22847942/java-interface-reference
👌3👍1
#sparkdate #sparktimestamp

Работа с типами дата и таймстамп заслуживает отдельного внимания в Apache Spark.
Особенно если есть джоины или фильтрация наборов данных по такого рода колонкам.
В таком случае все значения надо СТРОГО приводить к одному формату!
Иначе плакали наши данные и кино 🎥 показывать не будут.

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

Например timestamp или string с типом date джоинить нельзя. Иногда спарк сам может справиться с конвертацией и выдрать дату из таймстампа, НО это риск, который может вылезти в самый неожиданный момент.

https://spark-school.ru/blogs/timestamp-functions/
👍4
#completablefuture

Хорошее видео с разбором overhead'а при асинхронном выполнении и результатами замеров.

Мне понравился момент, когда автор в начале говорит, что перед началом исследования сделал пост в соц. сети с вопросом о использовании CompletableFuture и главным отзывом было - "нихрена непонятно как пользоваться".

Так же на 13 минуте приводиться несколько вариантов завершения. Это и есть фото в этом посте.

От себя отмечу, что CompletableFuture цепочки это аналог Stream API в Java и нужно быть внимательным с методами. Какие-то из них блокирующие, а какие-то нет.

🎥 Видео:
https://youtu.be/W7iK74YA5NM

Примеры кода:
https://liakh-aliaksandr.medium.com/asynchronous-programming-in-java-with-completablefuture-47ab86458aab
🤔1
This media is not supported in your browser
VIEW IN TELEGRAM
#codereview

Видео 🎥 показывает что переживает разраб сделавший доработки и создавший Pull Request для код ревью! От души!

https://habr.com/ru/company/selectel/blog/660947/
😁1😢1
#sparkdataframe

Могу сказать, что основной класс Dataset в спарке - это полная дичь:
1. Отсутствуют какие-либо Java docs, чтобы хоть понять можно было - что на самом деле будет делать тот или иной метод.
2. Типы джоинов надо указывать стрингом, пример - "left". Если ошибёшься - сам виноват.
3. Имена параметров в методах вообще непонятны. Возникает ощущение, что компания авторов была не совсем трезвая и писали имена полей упрощённо - "other".

Но несмотря на проблемы, этот класс поставляется как основной для работы с Apache Hadoop.

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

А пока вот описание:
https://www.baeldung.com/spark-dataframes
👍3
#javadoc

Пример кода в составе джавадока это не сложно.
Внутри фигурных скобок надо написать @code и далее описать как создать экземпляр класса и пользоваться методами.

https://www.baeldung.com/javadoc
👍3
#sparkcache #persist

Кэширование это тема.
Но перед тем как написать в коде .cache() надо взвесить - будет ли выхлоп с кэширования??

Стоит учесть, что это полезно ТОЛЬКО в том случае, когда есть многократное переиспользование одного и того же датафрейма!

Если как минимум 2 раза к КЭШИРОВАННОМУ датафрейму обращения не будет, то можно спокойно писать код и не занимайся этим кэшем.

Плюс отдельно надо сказать, что как правило оперативной памяти не хватает. Отсюда строгая рекомендация - если кэшировать, то только фильтрованный датафрейм! Например данные за сегодня или за интервал, но НЕ все данные гнать в память.

https://bigdataschool-ru.turbopages.org/turbo/bigdataschool.ru/s/blog/caching-in-spark-sql.html
👍3
#completionservice
#completablefuture

Отличный вопрос и пример кода асинхронной обработки taskов.
Надо сказать, что вопрос задан очень интересно🤔.

Ведь CompletionService предоставляет метод take() который может обрабатывать результат дальше по готовности без блокировки и ожидания потоков-соседей!

В данном случае CompletableFuture оказывается удобнее и богаче по набору методов для асинхронной обработки задач. Можно писать целые chainы логической последовательности действий.

Здесь кстати, чтобы разобраться в этом посте надо понимать что такое асинхронность вообще??

Вот видос от Luxsoft который поможет в этом разобраться!
https://youtu.be/yBF9VRiGkik


Ну и сама статья для примера:
https://stackoverflow.com/questions/63762096/completionservice-vs-completablefuture
👍4
#generics

Есть такие типы - дженерики называются. Ссылка для самообучения от javarush ниже.
Но сейчас не об этом.
Эта записка о том, что есть конвенция именования дженерик параметров ОДНОЙ ЗАГЛАВНОЙ БУКВОЙ.

Так вот, проблема в том, что на практике когда тебе нужны несколько параметров да ещё и с одинаковыми первыми буквами классов - это похоже на издевательство:
1. Не понятно по одной букве что за тип стоит за буквой.
2. Можно начать танцевать и добавить цифру к букве, НО читаемость это не сделает.

Поэтому удобнее делать дженерик типы по заглавным буквам интерфейса или класса.

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

Оказывается я не одинок в этой мысли, вот ссылка на беседу:
https://stackoverflow.com/a/33394836

Что такое дженерик типы:
https://javarush.com/groups/posts/2004-teorija-dzhenerikov-v-java-ili-gde-na-praktike-stavitjh-skobki
👍1
#ssd
#linuxmint

Мой жёсткий диск на ноутбуке сгорел ещё во время первой волны ковида при вынужденной работе из дома.
Добрался до замены - взял SSD Kingston вместо обычного для ускорения.
Ощущения от SSD хорошие - установка новой ОС Linux Mint заняла всего около 10 минут. Под разработку и обучение самое то - рекомендую!

Качнуть актуальную версию можно по ссылке:

https://linuxmint.com/download.php
👍2🔥2