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

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

Комплименты, вопросы, предложения: @utki_letyat
Download Telegram
Какой язык из перечисленных самый старый?
Anonymous Quiz
26%
Java
5%
JavaScript
9%
Ruby
33%
PHP
9%
C#
19%
Python
🔥365👎3
Зачем Redis для задач по расписанию?

На прошлой неделе писала про задачки по расписанию и аннотацию Scheduled. Сегодня расскажу интересный кейс, когда для такой задачи используется очередь Redis.

Типичная реакция джавистов: "Чего? Как? Зачем???"🤯

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

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

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

Основной сервис и сервис-исполнитель - это разные процессы, у них нет разделяемой памяти. Redis нужен, чтобы передать задачу из одного процесса в другой. Ну и как бонус — распределить задачки между исполнителями.

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

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

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

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

Зачем изучать подходы в других языках?

Как я писала в прошлом посте, модель многопоточности влияет на архитектуру и инфраструктуру. У каждого языка свои "стандартные решения". Если сервис написан на Python, надо подкручивать определенные настройки Redis. В JS модель многопоточности как в питоне, но задачи по расписанию чаще реализуют через crontab и Mongo.

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

И, конечно, инженерный интерес! У разных инструментов разные подходы, свои преимущества и ограничения. Разбираться, как и за счёт чего решаются задачи, оценивать трейдоффы и выбирать подходящее решение очень интересно. Такие задачки - мои самые любимые🥰
🔥89👍3614👎10
🔥14👍5
Как создать неблокирующий индекс в Postgres?

Сегодня расскажу про опцию CONCURRENTLY при построении индекса.

Идея проста. Обычный CREATE INDEX блокирует изменения в таблице, возможно только чтение данных. Пока индекс строится, запросы на запись подвисают. Блокировка может длиться от нескольких минут до часа. Вряд ли пользователям это понравится.

Опция CONCURRENTLY решает эту проблему и не блокирует обновления, с таблицей можно продолжать работать. Выглядит опция так:
CREATE INDEX CONCURRENTLY idx ON t(f);


Если всё так круто, почему опция не выбрана по умолчанию?

Потому что появляются новые проблемы.

Обычный индекс один раз проходит по таблице, которая не меняется, поэтому успех неизбежен.

Если индекс строится во время активной работы с базой — привет гонки, параллельные транзакции и вся классика многопоточных проблем. В итоге
▫️ Индекс строится гораздо дольше. Скан таблицы происходит 2 раза, индекс постоянно ждёт завершения транзакций и борется с внутренними противоречиями
▫️ Индекс может не получиться и остаться в статусе invalid. В таких случаях надо снести неполучившийся индекс и начать построение заново. Возможно не один раз💔

Второй важный момент, который касается неблокирующих индексов — партиционированные таблицы.

Если добавить обычный индекс для "основной" таблицы, для текущих и будущих(!) партиций индекс создаётся автоматически. Очень удобно

Но для CONCURRENTLY индекса такая схема не работает. Чтобы создать неблокирующие индексы для партиций придётся делать так:
▫️ Создать индекс на "основную" таблицу
▫️ Создать неблокирующий индекс для каждой партиции
▫️ Присоединить эти индексы к "основному"

Примерно так:
CREATE INDEX idx ON ONLY t(f);
CREATE INDEX CONCURRENTLY p1_idx ON p1_t(f);
ALTER INDEX idx ATTACH PARTITION p1_idx;


В общем, при создании индекса для большой таблицы придётся делать выбор:
🪑 CREATE INDEX и заблокировать работу с таблицей на десятки минут
🪑 CREATE INDEX CONCURRENTLY и выполнить кучу дополнительной работы, но меньше затронуть пользователя

Универсального решения нет, выбираем стул в зависимости от ситуации:)
👍86🔥5219
Как подготовиться к собесам на Middle/Senior позицию и заполнить пробелы по самым горячим навыкам на рынке

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

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

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

@awesome_java_bot

Как это работает: каждый день бот спрашивает несколько вопросов. Основные темы: Java, БД, Спринг, Кафка, многопоточка, микросервисы. 

💪 Ответили правильно → +5 к уверенности в своих навыках
💪 Что-то пошло не так → читаете пояснение к вопросу, это если побыстрее. Если хотите углубиться, читаете конспект из базы знаний и доп.материалы.

Кому точно надо:
Если планируете осенний рейд по собесам. Тогда надо 100000%
Если хотите подтянуть знания и заполнить пробелы по популярным на рынке технологиям

Бот платный. Есть 3 пробных дня, чтобы оценить формат и убедиться, что уровень материалов топ. Для любимых подписчиков сниженная цена до вечера пятницы, потом будет дороже

@awesome_java_bot

Формат у бота слегка непривычный, но, уверена, что вы разберетесь:)
🔥97👍2015👎14
Последний день скидки

Ну что, вот и прошло 3 дня после анонса бота. Спасибо тем, кто поддерживал и тем, кто взял подписку❤️

Хочу ответить на вопрос, который задавали в том или ином виде:
В интернете есть списки вопросов, на ютубе мок собесы, а ещё ИИ, чем бот лучше?


Вместо тысячи слов - возьмите пробный период и оцените сами

@awesome_java_bot

А если хочется слов, вот 4 главных плюса:

1️⃣ Вопросы

Вопросы крутятся вокруг тем и моментов, с которыми у многих случаются сложности. Это не просто список с собесов. Я дополнила их вопросами на понимание, вопросами-кейсами, формулировками с другого ракурса.

В одном отзыве на курс многопоточки ученик написал, что я использую метод Сократа. Из википедии:
Этот метод часто подразумевает дискуссию, в которой собеседник, отвечая на заданные вопросы, высказывает суждения, обнаруживая свои знания или, напротив, своё неведение.


Это прекрасно описывает стратегию бота. Многие вопросы не встречаются на собеседовании в явном виде, но помогают найти пробелы в знаниях или понимании темы.

Ни одна нейросеть не соберёт вам такое.

2️⃣ Активная работа

Читать списки вопросов или смотреть видео - это пассивное потребление информации. Мозг включается минимально, кажется, что всё понятно и легко. А через минуту забываешь, что вообще смотрел и читал.

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

Плюс мгновенная обратная связь. Сразу понятно, есть ли пробел с какой-то темой или всё чётко.

3️⃣ Материалы

Краткое пояснение, конспект в базе знаний, ссылки на доп.материалы. Удобно и экономит время.

4️⃣ Напоминания

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

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

Сейчас это копейки. Плюс до конца дня действует скидка для любимых подписчиков. Отличный шанс зафиксировать низкую цену:

@awesome_java_bot

Популярный вопрос - можно ли оплатить не российской картой? Можно🌸
🔥3010👍10
Релиз Java 25

будет завтра. А сегодня - краткий обзор фич новой версии.

Пропущу JEP в статусе Preview, хотя среди них много интересных вроде Stable Values или Structured Concurrency. Расскажу только о новшествах, которые обрели финальную форму.

🍑 JEP 519: Compact Object Headers

Самая полезная фича в новом релизе. В чем суть. У каждого объекта есть заголовок, в котором хранится служебная информация для JVM.

В Java 25 размер заголовка сократился с 12 байт до 8.

Вроде немного, но в одном бенчмарке это сэкономило аж 22% памяти и 8% CPU. В реальных приложениях результат будет скромнее, но всё равно приятно.

Включается флажком -XX:+UseCompactObjectHeaders, по умолчанию Compact Headers выключены.

Следующие 2 фичи вряд ли потребуются каждый день, но знать о них стоит.

🍑 JEP 513: Flexible Constructor Bodies

Писала о них отдельный пост, поэтому кратко - в конструкторах перед вызовом super можно добавить проверки аргументов:
class Employee extends Person {
  Employee(int age) {
    if (age < 18)
        throw new IllegalArgumentException(...);
    super(age);
  }
}


🍑 JEP 506: Scoped Values

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

Традиционно для этих целей используется ThreadLocal. Яркий пример - SecurityContext из Spring Security. Мы не тащим SecurityContext в каждый метод, но информация о текущем пользователе всегда под рукой.

Scoped Value - это ThreadLocal Premium:
👑 Доступен только в пределах заданной области
👑 Значение неизменяемое
👑 Автоматически удаляется после использования
👑 Совместим с виртуальными потоками

Остальные фичи довольно специфичны, опишу их кратко

🍑 JEP 510: Key Derivation Function API

Квантовые компьютеры активно развиваются, они очень мощные и будут щёлкать текущие алгоритмы как орешки. Этот JEP - часть работ по внедрению в джаву Post-Quantum Cryptography - новых алгоритмов безопасности.

🍑 JEP 511: Импорт модулей

Вместо
import java.util.*; 
import java.util.function.*;
import java.util.stream.*;

Можно написать короче:
import module java.base;

Любая IDE управляет импортами за нас, поэтому полезность фичи под вопросом. Возможно, разработчики джавы не вспомнили названия модулей, когда подтверждали свои навыки на HH. Но это не точно.

🍑 JEP 503: Remove the 32-bit x86 Port

Не учитывать в дальнейшей разработке 32х-битные процессоры

🍑 JEP 512: Compact Source Files and Instance Main Methods

Более короткий Hello World:
void main() { 
  IO.println("Hello, World!");
}


🍑 JEP 520: JFR Method Timing & Tracing, JEP 515: Ahead-of-Time Method Profiling, JEP 520: JFR Method Timing & Tracing

Профайлинг стал точнее и стартует чуть быстрее.

🍑 JEP 521: Generational Shenandoah

Сборщик мусора Shenandoah теперь делит объекты на старые и новые, раньше это была экспериментальная фича.

Такой вот релиз будет завтра
🔥116👍4115
Spring и паттерн Singleton

В мае я писала про групповой транс на собеседованиях при обсуждении SOLID. Люди на автомате обмениваются дежурными фразами, совершенно не вслушиваясь в суть. Сегодня расскажу ещё один пример.

Часто на собесах обсуждается паттерн Singleton примерно в таком ключе:

🤵‍♀️: Синглтон - это когда один экземпляр на приложение
💁: А пример привести можете, где он встречается?
🤵‍♀️: Ну, бины в спринге
💁: Ага, ок


Вроде логично. У бинов по умолчанию скоуп Singleton. Создаётся один экземпляр. Значит, бины по умолчанию синглтоны.

Но нет.

Суть паттерна Singleton не в том, что в приложении один экземпляр класса. А в том, что он гарантированно один, и никаким легальным способом в системе не может появиться ещё один экземпляр. Для этого проводится комплекс мер - конструктор становится приватным, доступ к объекту предоставляется только через метод. Плюс всякие приёмы для ленивой инициализации и thread-safe.

В случае спринга таких мер нет:
👯‍♀️ Можно создать 2 бина одного типа
👯‍♀️ Можно в любом месте сделать new

Scope Singleton означает лишь, что бин с таким id будет в контексте один. Но это не реализация паттерна Singleton.

———————————————
Фан факт для зумеров: слово "синглтон" активно использовалось в районе 2010, чтобы обозначить людей, которые живут одни и довольны этим. В газетах были статьи типа "Я - синглтон", а в новостях — сюжеты, что в России "расцветает синглтонство".
🔥69👍32👎1410
SemVer и как меня расстроил JUnit 6

Эта осень богата на релизы. Недавно вышла Java 25, в ноябре выйдет Spring 7 и Spring Boot 4. Другие библиотеки тоже выпускают обновления. Сегодня обратим внимание на два камбэка:
JUnit 6. Пятая версия вышла 8 лет назад, в 2017 году
Jackson 3. Jackson - верный помощник в перекладывании джейсонов, вторая версия вышла больше 10 лет назад

Когда выходит новая версия после большого перерыва, душа трепетно ждёт серьезных изменений. Потом смотришь release notes, а там все скучно. Что-то переименовали, что-то удалили, повысили версию джавы😒

Но если нет ничего нового, зачем повышать версию?

Ответ прост. На большинстве проектов используется семантическое версионирование (SemVer) - популярное соглашение о формате версий. Оно задаёт формат MAJOR.MINOR.PATCH, где
▫️ MAJOR — мажорная версия, меняется при несовместимых изменениях API
▫️ MINOR — минорная версия, добавляет функциональность с обратной совместимостью
▫️ PATCH — меняется при исправлении багов

Дополнительно в версии может быть номер билда, целевой стенд или пользователь, который запустил сборку. Может быть префикс/суффикс/тег, чтобы подчеркнуть особый статус билда. Например, у сборок Spring
🌸 6.2.0-RC3 - release candidate. Билд с зафиксированным набором фич для интенсивного тестирования
🌸 7.0.0-M9. М значит Milestone, большие изменения для сбора обратной связи и тестирования

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

Но это теория. От ожиданий никуда не деться. Даже за пределами IT люди ждут значимых изменений от мажорных версий. Новый айфон, новая модель нейронки. Я вот расстроилась, что в JUnit 6 не завезли ничего интересного💔

Ну да ладно. Зачем нужно знание SemVer на практике?

Чтобы планировать масштаб работ для обновления. При апдейте спринга с 6.1 на 6.2 скорее всего проблем не будет. А вот переход 6.2 -> 7 может затянуться. Кто обновлял Spring Boot со второй версии на третью и менял тысячу импортов - жмите ❤️. Переход Jackson 2 -> Jackson 3 очень похож, основная работа при апдейте - это замена com.fasterxml.jackson на tools.jackson.

Если в JUnit 6 и Jackson 3  ничего особенного, зачем обновляться?

Потому что Spring 7 использует эти новые версии. Если захотите обновить спринг, придётся обновить и эти библиотеки. Так что это неизбежно🌚
161🔥34👍29👎6
Распределенный лок

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

Небольшое интро.

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

В чем сложность работы с распределенным локом?

В комбинации "сложный алгоритм + общение по сети". Работа с локом — это не просто "взял-отпустил". Полный цикл выглядит так:
Создать лок -> Попытаться захватить -> Если не получилось: попробовать ещё раз или встать в очередь -> Отпустить -> Удалить

Каждый участник в любой момент может отвалиться, а запрос - задержаться. В итоге получаем мешок вопросов, которые нужно обдумать:
Что делать, если сервис взял лок, но умер?
Что будет, если один сервис отправит 2 команды захватить лок?
Может ли сервис отпустить лок, который он не держит?
Что делать, если порядок запросов нарушится, и сначала на лок пришла команда "отпустить", а потом "взять"?
Кто будет создавать локи?
Будет ли атомарно работать связка "создать и захватить лок"?
Сколько сервис будет пытаться захватить лок? С какими интервалами?
Если сервис встаёт в очередь к локу - сколько времени ждать? можно ли выйти из очереди?
Кто и когда будет удалять локи?

Многие вопросы снимаются инструментами, но не все. Race condition в распределенных системах встречается сплошь и рядом. Взять хотя бы недавний сбой Амазона, где всё началось с того, что 2 сервера одновременно накатывали апдейт и помешали друг другу.

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

Поэтому даже если система маленькая, всё крутится на одном сервере и сетевые проблемы сведены к минимуму, рекомендую рассмотреть альтернативы. Например
✔️ Сделать задачу идемпотентной и безопасной для многократного выполнения
✔️ Провернуть Inversion of control. Ресурсы распределяются по исполнителям, а не исполнители борются за ресурсы

Оба подхода можно протестировать, и общая логика часто упрощается. Берите на заметку, квинтэссенция многолетнего опыта:)

Но если сердце не видит преград, и сделать лок хочется, вот пара заметок:
💫 Лок можно реализовать на Postgres (SELECT … FOR UPDATE), Redis, Zookeeper, Kubernetes. Гляньте библиотеку ShedLock
💫 ID держателя лока удобно записывать в лок. ID каждого участника должен быть постоянным
💫 Вместо плясок с TTL можно положиться на связь сервиса и лока. В Zookeeper есть ephemeral nodes, которые исчезают, если связь с сервисом пропадает. Транзакция в Postgres может не сразу обнаружить разрыв соединения, но тоже в итоге откатится

Что почитать:
🔥 Cтатья Alibaba Cloud 2024 года. Обзор решений на джаве и их нюансов
🔥 Статья Клепмана (автор книги с кабанчиком) про недостатки распределенного лока в Redis . Статья старая (2016 год) и специфичная, но полезна для полноты картины
🔥79👍3224👎3
Value types: основное

На прошлой неделе вышел билд с реализацией value types и основными оптимизациями. Это даже не превью версия, детали ещё поменяются, но первое впечатление составить уже можно. Вся информация есть в JEP 401.

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

Интро

В java 2 гендера типа сущностей — примитивы и ссылочные типы. К первой группе относятся int, long, boolean и тд. В таких переменных хранится само значение. Набор действий с примитивами ограничен, зато вычисления происходят с космической скоростью.

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

Цель value типов - взять лучшее из двух миров: удобство классов и скорость примитивов. Добавляется ключевое слово value, которое ставится перед классом:
value class LocalDate {
   int year;
   int month;
   int day;
   // конструкторы, методы
}

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

Глядите на картинку👇 Слева список объектов, справа - набор value. Работа со списками обещает быть blazingly fast🚀

Value types прекрасно вписываются в текущие тренды. Сейчас через сервисы проходит море данных, которые в большинстве своём неизменяемые. Уплощение структуры даст буст в скорости обработки. Поэтому value types так ждут.

Модификатор value уже получили 30 базовых классов:
▫️ обёртки примитивов: Integer, Long, …
▫️ Optional*
▫️ классы дат: LocalDate, LocalDateTime, …

Классы выше - база, поэтому перфоманс подрастёт просто при переходе на JDK с value типами. Такое мы любим.

Ещё немного странного/интересного:

🤔 value можно добавить абстрактному классу. Тогда наследники тоже станут value классами. В JEP написано, что наследники могут отказаться от value модификатора, но как - непонятно:)

🤔 value class vs record

Record - final класс с final полями, идеальный кандидат, чтобы стать value классом по умолчанию. Но это не так, для records нужно явно прописывать value. В самом JEP объяснение сводится к утверждению
Не каждый value класс можно сделать record

Что, безусловно, верно. Но непонятно, почему неверно обратное. Остаётся только додумывать про обратную совместимость с уже существующими рекордс

🤔 String не стал value классом

Опять же, могу найти техническую причину. Хэш строки вычисляется лениво, а в value классе поля должны быть final. Здесь помогла бы другая фича, которая сейчас в превью — StableValue, ленивая инициализация final полей.

Но в JEP пишут, что дело в наличии идентичности (identity) у строки. Про концепт идентичности напишу отдельный пост, но если кратко: identity определяет возможность сравнения 2 объектов с одинаковыми значениями.

Почему у строк есть identity, мне непонятно. Пул строк, дедупликация и прочие оптимизации явно не уважают право String на идентичность.

Это только основное, на что точно следует обратить внимание. В тексте ещё очень много интересного, куча намёков на будущие фичи и оптимизации. Давно не читала JEP с таким интересом😊
🔥101👍5029👎2
Integer v1 = 2000; Integer v2 = 2000; Что напечатает System.out.println(v1 == v2)?
Anonymous Poll
22%
true
78%
false
Value types: концепт идентичности

Сегодня продолжу разбирать JEP 401: value types. Начало в прошлом посте.

В JEP слово identity встречается 87 раз, практически в каждом абзаце. В этом посте разберу концепт идентичности и что меня в нём смущает.

В систему типов вводится новый термин - идентичность (identity):
▫️ У примитивов идентичности нет. 10 в одном месте ничем не отличается от 10 в другом месте
▫️ У ссылочных типов идентичность есть, каждый объект уникален. 2 объекта UserDTO - это разные объекты, даже если поля одинаковые
▫️ У value классов идентичности нет

С первого взгляда кажется, что идентичность это про == и equals. Но по мере чтения JEP растёт ощущение, что что-то не так. Например

1️⃣ Нет чёткого определения идентичности

Понятия типа identity относятся больше к проектированию модели данных. Value object, агрегаты и прочий DDD.

Java — это всё ещё язык программирования уровня циклы/классы. Примитивы и ссылочные типы описываются техническими характеристиками - стек, куча, наличие методов и тд.

Идейно Identity — что-то про возможность сравнения объектов между собой. Но что это означает с технической точки зрения в java — непонятно.

2️⃣ Сравнение value типов описано в JEP очень противоречиво:

💁🏼 С одной стороны, много раз повторили, что == сравнивает value объекты по значению полей. Как в примитивах, 123 == 123
🙋🏼 Но для некоторых value объектов equals вернет true, а == вернет false. Поэтому жирным шрифтом рекомендуют использовать equals

value класс - это всё ещё класс. Маловероятно, что кто-то будет использовать == для сравнения объектов. И объяснение какое-то есть. Но осадочек, что тема мутная, всё равно остаётся.

🌚 Конспирологическая теория, зачем на самом деле нужна identity

Внятного определения идентичности нет, значит понятие само по себе не важно. Гораздо важнее, что такое "тип без индентичности". Здесь написано чётко. Тип без идентичности
▫️ Immutable: неизменяемый
▫️ Interchangeable: взаимозаменяемый. Необязательно различать две сущности, если у них одинаковые значения

Для сущностей с этими свойствами добавляется пачка оптимизаций. Помимо уплощения кучи в списках есть, например, такая:
При создании value объекта через new, JVM может не создавать новый объект, а найти уже такой же существующий. == для таких объектов будет возвращать true.

Подобная идея лежит в основе пулов для базовых типов. При вызове Integer.valueOf(127) не создаётся новый объект, а берётся уже существующий из пула. Для классов-обёрток это существенная экономия.

Текущая цель модификатора value и концепта identity (вернее его отсутствия) - обозначить, к каким объектам можно применить пачку оптимизаций.

Новый тип и рассуждение про доменные сущности выглядит пока натянуто. Нужно явно обозначить определения, границы и ожидаемые эффекты от value. Типы данных - база, одна из первых тем при освоении языка. Должно быть простое объяснение, чем отличаются типы, без погружения в дебри возможных оптимизаций. Должно быть конкретное определение identity, если оно важно для выбора типа.

Годы работы и преподавания не проходят бесследно. Если что-то может быть понятно неверно - оно будет понято неверно💯 Поэтому пока оцениваю новую фичу на троечку

И ответ на вопрос перед постом. Сейчас в консоли будет false, объекты сравниваются по ссылке. Возможно, после введения value types тот же код вернёт true, и популярный вопрос с собеседований получит вторую жизнь. Но может и нет💅
👍51🔥2514👎4