Java: fill the gaps
12.9K subscribers
7 photos
215 links
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк

🔥Тот самый курс по многопочке🔥
https://fillthegaps.ru/mt

Комплименты, вопросы, предложения: @utki_letyat
Download Telegram
JDK, JRE, JVM, JIT и Java 11

Как связаны между собой эти аббревиатуры и что изменилось в java 11?

Жизненный цикл кода обычно описывают так:
1️⃣ Программист с помощью IDE (или блокнота) создаёт файлы с расширением .java
2️⃣ IDE или утилита javac компилирует их в байткод — файлы с расширением .class
3️⃣ JVM интерпретирует байткод в системные вызовы конкретной платформы.

Эта терминология не совсем точная. JVM — всего лишь спецификация, она предоставляет интерфейс для работы с классами, потоками, памятью, сборщиком мусора и тд. Это абстрактная сущность, физически её не существует.

Многие компании реализуют JVM - HotSpot, Azul, Excelsior и тд. Их продукт позволяет запускать программы и называется JRE (Java Runtime Environment). Помимо указанных в JVM методов JRE содержит библиотеки основных классов(rt.jar) и JIT(Just-in-time)-компилятор.
JVM функции обычно интерпретируются - просто исполняются строка за строкой. JIT-компилятор оптимизирует байткод для конкретной платформы и подставляет машинные команды прямо во время работы. Это сильно увеличивает производительность.

JDK(Java Development Kit) позволяет создавать и запускать программы. Он состоит из JRE и инструментов разработки, таких как компилятор javac, дебаггер jdb, генератор документации javadoc, архиватор jar и тд.

Кратко отношения между сущностями выглядят так:
JVM = спецификация
JRE = реализация JVM + JIT-compiler + библиотеки
JDK = JRE + инструменты разработки

JDK нужны только программистам, а тестовому окружению и продакшену для запуска программ хватает JRE. Поэтому на сайте вендоров JVM обычно представлены оба этих варианта - JDK и JRE для разных платформ.

Но всё изменилось после выхода Java 11. Теперь для скачивания доступна только JDK, а JRE отдельно не поставляется. Чтобы создать среду исполнения используется специальная утилита jlink, в ней указываются необходимые для приложения модули. Редко какой программе нужны все 75 модулей, поэтому полученная JRE занимает гораздо меньше памяти, не содержит лишних библиотек и работает быстрее.

Решение ориентировано на модульную архитектуру, тренд на которую начался в java 9. Второй фактор - популярность использования java на устройствах IoT. Здесь ключевую роль играет компактность JRE и ограниченность функций для повышения безопасности.

Cписок используемых модулей помогает получить утилита jdeps. К счастью, все популярные IDE уже поддерживают java 9, поэтому Вам вряд ли придётся самостоятельно формировать module-info.

#теория
👍4
Сегодня вышла JDK 14!

16 обновлений, среди которых:
компактный синтаксис record,
улучшенный switch,
многострочные текстовые блоки,
информативные NPE,
приведение типа прямо в instanceof.
2
Утренний java puzzle♨️

Сегодня разберём очень популярный вопрос на собеседованиях. Проверьте себя, а через час выйдет статья. Там будет правильный ответ и 3 бонуса, чтобы покорить сердце любого интервьюера
Integer a = 100;
Integer b = 100;
System.out.println(a == b);
Anonymous Poll
58%
true
31%
false
10%
когда как🤷‍♂️
Сравнение переменных на собеседованиях.

Начнём с основ. Переменная — именованное место в памяти для хранения какого-либо значения. Переменные в java делятся на 2 группы:
1️⃣ примитивные типы — int, char, long и тд. У них в памяти хранится само значение, поэтому следующий код выведет true:
int a = 500;
int b = 500;
System.out.println(a == b);
// true


2️⃣ ссылочные типы — Integer, Long, String и тд. Где-то в памяти лежит объект, а в этой переменной хранится указатель на него. При использовании оператора == сравниваются только ссылки, а не сами объекты. Поэтому даже если они по сути одинаковые, операция == вернёт false:
Integer a = 500;
Integer b = 500;
System.out.println(a == b);
// false


В рабочих проектах мы чаще работаем с объектами. А ещё часто используем небольшие числа, например, в циклах и счётчиках. Чтобы сократить количество создаваемых объектов, в java есть кэш для чисел от -128 до 127. Поэтому следующий код вернёт true:
Integer a = 100;
Integer b = 100;
System.out.println(a == b);
// true


Это правильный ответ на вопрос из предыдущего поста.
Примечание: это верно только при такой форме записи. Если использовать оператор new, то будет создан отдельный объект в памяти. Сравнение ссылок на два разных объекта всегда возвращает false:
Integer a = new Integer(50);
Integer b = 50;
System.out.println(a == b);
// false


Это базовая теоретическая часть, знакомая многим. Но на собеседовании нужно показать себя во всей красе, поэтому обязательно упомяните следующие 3 факта. Они серьёзно повысят Ваш рейтинг среди других кандидатов.
1️⃣ Для сравнения ссылочных типов по значению используется метод equals.
2️⃣ Механизм кэширования есть для Integer, Long, Byte, Short, Boolean и Character.
Нет для Float и Double.
3️⃣ Только для Integer — можно выставить значение верхнего диапазона кэширования с помощью опции VM. Если написать
-XX:AutoBoxCacheMax=2000
то закэшируются все Integer в диапазоне от -127 до 2000:
Integer a = 500;
Integer b = 500;
System.out.println(a == b);
// true

Вернёмся к исходному вопросу из предыдущего поста. Правильный ответ – true, но знание факта №3 даёт право отвечать на него «когда как».
👍7
Принцип подстановки Барбары Лисков: теория и практика.

SOLID - акроним, который содержит важные принципы объектно-ориентированного проектирования. Третий из них — Liskov Substitution Principle (LSP) часто вызывает трудности с пониманием из-за запутанной формулировки:
Пусть q(x) является свойством верным относительно объектов x некоторого типа T. Тогда q(y) также должно быть верным для объектов y типа S, где S является подтипом типа T.
По-простому: если заменить класс А на подкласс B, то система должна работать корректно и без неожиданных сайд-эффектов.
A service = new A();
A service = new B();
//всё ок


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

5 признаков того, что подкласс реализован правильно:
Синтаксические (для методов)
1️⃣ тип результата в переопределённом методе такой же, либо расширенный
Было: public Info getInfo()
public BigInfo getInfo()
public Object getInfo()
2️⃣ Подклассы не бросают дополнительных исключений, но могут уменьшить их список:
Было: public void save() throws FileNotFoundException
public void save()
public void save() throws InterruptedException
Java — типизированный язык, поэтому нарушения пунктов 1 и 2 контролируются компилятором.
3️⃣ типы параметров функций те же или менее строгие. Для Java это неприменимо, просто для справки:
Было: public void add(Account acc)
public void add(Object acc)
public void add(AdminAccount acc)
Поведенческие признаки:
4️⃣ метод подкласса делает то же, что и метод базового класса:
▪️если базовый метод countVisitors() только считает пользователей, то метод подкласса тоже должен просто считать пользователей, а не обновлять статистику и сохранять результат в БД.
5️⃣ метод подкласса взаимодействует с теми же сущностями, что и базовый
▪️ если в базовом методе увеличивается счётчик, то и в подклассе он увеличивается.
▪️ если в базовом классе есть переменная, которую базовый метод не меняет, то переопределённый метод тоже не должен её менять.
▪️ сценарии работы — если базовый класс предусматривает определённый порядок вызова методов, то подкласс тоже соблюдает этот протокол.

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

Вообще наследование — очень сильная связь между сущностями. Её ограничения могут перевесить преимущества по ходу развития проекта. Нарушения принципа подстановки — повод пересмотреть иерархию наследования или же вовсе от неё отказаться.
👍31
24 плагина Intellij IDEA для работы и души.

Сейчас на маркетплейсе IDE доступно больше 4 тысяч плагинов. Платные и бесплатные, они здорово помогают в решении ежедневных задач. Устанавливайте нужные вам и работайте комфортно и эффективно.

Работать с БД
▪️Database Navigator для RDBMS
▪️Mongo Plugin
▪️ledis для Redis
▪️Graph Database support для Neo4j

Установить единый кодстайл
Плагин и общий конфиг для команды помогут писать код единообразно
▪️CheckStyle-IDEA
▪️SonarLint

Найти баги
FindBugs-IDEA проверяет код на 200+ ошибочных паттернов

Решить проблемы с зависимостями
Maven Helper plugin поможет выявить конфликты и циклические зависимости

Править bash-скрипты
гораздо проще с плагином BashSupport

Увеличить скорость работы с IDE
Key promoter X научит сочетаниям клавиш для максимальной продуктивности

Проверить регулярные выражения
RegexpTester

Наглядно представить верхнеуровневые задачи
IDEA Mind Map для декомпозиции задач и мозговых штурмов

Легко ориентироваться в уровнях вложенности
▪️Rainbow Brackets - разноцветные скобки
▪️Indent Rainbow - разноцветные отступы

Почувствовать себя музыкантом
Fancy Music добавит звуки фортепиано для каждого нажатия клавиатуры

Поделиться кодом в Твиттере
▪️TweetCode
▪️IdeaTweet

Добавить спецэффекты
Power Mode II для эпичного кодинга

Поставить классный прогресс бар
▪️Nyan Progress Bar с радужной кошечкой
▪️Duck Progress Bar - для любителей уточек
▪️Hadouken Progress Bar - для уличных бойцов
▪️Dash Progress Bar - для тех, кто всегда готов постоять за друзей
▪️SSV Normandy Progress Bar - для фанатов Mass Effect
▪️StarTrek Progress Bar - для тех, у кого "Энтерпрайз" ассоциируется не только с работой
3
Утренний java puzzle♨️

Проверь себя и узнай правильный ответ в статье через час.
Сколько видов сборщика мусора есть в java на сегодняшний день?
Anonymous Poll
49%
4
34%
5
17%
6
Сборщики мусора. Плюсы и минусы 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 адаптируется к нагрузке и прекрасно работает со значениями по умолчанию.
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 могут быть не только про кофе и многословность😉
Сколько времени Вы можете отвечать на вопрос "как создать поток"?
Anonymous Poll
75%
До 5 минут
16%
5-15 минут
9%
15-60 минут
Как создать поток: 7 вариантов ответа.

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

1️⃣ Синтаксический ответ — ожидаемый.
🅰️ реализовать интерфейс Runnable или Callable и передать новому объекту Thread:
Runnable action = () -> System.out.println("hey");
new Thread(action).start();
🅱️ расширить класс Thread, переопределить метод run, создать экземпляр этого класса:
class MyThread extends Thread {...}
new MyThread().star
t();

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️⃣ Менеджерский ответ.
Рассмотрим поток с нетехнической точки зрения. Поток - состояние, когда человек полностью включен в свою деятельность, совершенно сконцентрирован на ней и испытывает удовольствие от работы.
Задача руководителя - создать сотрудникам подходящие для этого условия. Можно использовать множество методов: регулярная обратная связь, увеличения прозрачности процессов и т.д.

Ответ на банальный вопрос "как создать поток" может различаться в зависимости от опыта и текущей должности. Вопросы на собеседованиях - лишь стартовая точка для обсуждений, не стесняйтесь повернуть разговор на обсуждение Ваших компетенций и сильных сторон.
👍52🔥1
Собеседование: план рассказа о прошлом опыте.

Техническое собеседование обычно состоит из трёх частей:
1️⃣ Синтаксические и алгоритмические задачки
2️⃣ Рассказ о прошлом опыте
3️⃣ Вопросы на свободную тему

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

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

🔶️Проекты, над которыми Вы работали больше 2 лет назад. 2-3 предложения о теме проекта и основных технологиях.
🔶️ Предпоследний проект — год-полтора назад. Тоже кратко, 4-5 предложений.
🔶️ Последний проект. Это самая актуальная и важная информация, поэтому уделите описанию большую часть времени.

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

Такое описание проектов максимально выделит Ваши навыки и достижения. Интервьюер увидит, что Вы:
▪️понимаете задачи бизнеса
▪️видите общую картину и свой вклад в неё
▪️понимаете процессы внутри команды
▪️умеете решать проблемы
▪️ориентированы на результат

Помните, что направление рассказа о предыдущем опыте — не углубляться в технические детали, а показать, что Вы ответственный сотрудник, решаете поставленные задачи и хорошо работаете в команде.
Ведь именно этого ждёт будущий работодатель.
👍2
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.
👍31
Виш-лист разработчика: работа в стартапе и зарплата в долларах.

Пост рекламный, но о важных вещах.

В карьере разработчика сложны только первые шаги — войти в индустрию и набрать 3-4 года опыта. Спрос на программистов сильно превышает предложение, поэтому в IT большие возможности для самореализации.
Можно продвигаться в карьере, увеличивать зарплату или устраивать себе челленджи, например:
🔸️ Пройти путь от джуниора до архитектора за 5 лет.
🔸️ Разобраться в какой-нибудь теме, выступить на конференции и носить футболку с шуткой, которую поймут только 3 человека в мире.
🔸️ Пройти 8 этапов собеседований в Яндексе и отказаться от оффера.

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

Конечно, также велика вероятность:
▪️ ненормированного рабочего дня,
▪️ истеричных коллег,
▪️ закрытия проекта через 3 месяца.

Многие только после работы в стартапе поняли, что значить РАБОТАТЬ. Не закрывать задачи в джире и лениво отчитываться на стендапах, а решать проблемы здесь и сейчас, адаптироваться к изменениям, быстро внедрять новые технологии.

Работа с иностранными заказчиками — тоже специфический опыт. Удалённая работа, высокая зарплата, иностранный язык и иногда совсем другой менталитет.

Главная сложность — найти такие вакансии. На HeadHunter они если и появляются, то под названием «ИП Иванов А.И» или «ООО НьюСофт». Чаще всего их там нет🤷‍♂️

@profunctor_jobs — телеграм канал с супергорячими вакансиями и важной информацией — стек, зарплата, локация, график и контакт. Там ищут не только java разработчиков, но это реальный шанс найти интересные предложения. Среди их партнёров:
🤳Snap - компания владеет мессенджером Snapchat, умными очками Spectacles, сервисами Bitmoji и Zenly.
🚗Bolt – транспортная платформа, работающая в 30 странах.
💲Revolut – мультивалютные карты без процентов за конвертацию.

Рекомендуем подписаться и следить за вакансиями: @profunctor_jobs
Сколько лет Вы пишете на java?
Anonymous Poll
39%
Меньше года
35%
1-2 года
12%
3-4 года
14%
Больше 4 лет
Привет! Чтобы писать понятные и полезные посты, мы хотим знать больше о Вас и о том, что Вам интересно. Ответьте, пожалуйста, на 2 вопроса выше☝️
Ещё 4 коротких вопроса в https://forms.gle/Vqdfpjfm59BmPQBa6