Java Talks
Иконка канала Java Talks

Java Talks

1 подписчик

Джун использует Collectors.toMap без merge-функции. Если в стриме встречаются два элемента с одинаковым ключом, приложение падает с IllegalStateException: Duplicate key. На первый взгляд всё работает, пока данные не подкинут сюрприз. Почему так? Collectors.toMap без третьего аргумента внутри использует HashMap::put, который при дубликате ключа выбрасывает исключение. Это защита от случайной потери данных. Но если дубликаты для бизнес-логики допустимы, нужно явно указать, как разрешать конфликт. ⚠️ Нюанс: Collectors.toMap по умолчанию возвращает HashMap (без гарантии порядка). Если нужен порядок вставки — используйте четвёртый аргумент. #джава #javatutorial

1просмотр

Джун использует обычный int с synchronized для простого счётчика, создавая лишние блокировки и замедляя код. Сеньор знает про AtomicInteger — быстрый и потокобезопасный инструмент, работающий на CAS (compare-and-swap). Почему это круто? AtomicInteger обеспечивает атомарность операций без блокировок, используя низкоуровневые инструкции процессора. Потоки не блокируются в ожидании доступа к переменной, а пробуют снова, если другой поток уже изменил значение. Такой подход часто быстрее synchronized, особенно при низкой конкуренции. Но важно помнить: одна операция атомарна, а цепочка операций — нет. Для составных действий нужен compareAndSet в цикле или синхронизация. ⚠️ Нюанс: AtomicInteger гарантирует атомарность только одной операции. Если нужно атомарно выполнить последовательность (проверить + изменить), используй compareAndSet в цикле или синхронизацию. И помни, что updateAndGet — это более краткий способ атомарного обновления. #джава #javatutorial

1просмотр

❌ Джун задаёт значение в ThreadLocal и забывает его очистить. В пуле потоков один и тот же поток может быть переиспользован для следующей задачи, и данные «протекают» — новый запрос видит чужие конфиденциальные данные или состояние. Почему так? ThreadLocal хранит переменные в карте, привязанной к текущему потоку. В серверных приложениях (Tomcat, пул потоков ExecutorService) потоки не умирают после задачи, а возвращаются в пул. Если перед возвращением не вызвать remove(), следующая задача, выполняющаяся на этом же потоке, унаследует все оставленные значения. ⚠️ Нюанс: InheritableThreadLocal в пулах потоков не работает как ожидается — дочерние потоки редко создаются напрямую из задач. #джава #javatutorial

2просмотра

Джун переходит на var и начинает писать его везде. Код становится короче, но тип переменной теперь спрятан — чтобы понять, что именно возвращает метод, нужно прыгать в его реализацию. Читаемость страдает, особенно при код-ревью. Почему это проблема? var был введён в Java 10 для сокращения ceremony-кода, но его создатели сразу предупредили: используйте var только там, где тип очевиден из контекста. Если справа стоит конструктор (new HashMap()), литерал (List.of(...)) или статический фабричный метод с говорящим именем — var оправдан. Если вызывается произвольный метод без ясного возвращаемого типа — лучше объявить тип явно. Это ускоряет понимание кода и уменьшает когнитивную нагрузку. ✅ Как правильно? Писать явно, когда тип неочевиден. ⚠️ Нюанс: var нельзя использовать для полей класса, параметров методов и возвращаемых типов — только для локальных переменных с инициализацией. #java #джава #javadeveloper #javatutorial #javaprogramming

1просмотр

Код выглядит как гарантированный NullPointerException, но выполняется без ошибок. Метод вызывается, программа продолжает работу, а джун недоумевает, почему не упало. Почему так? Статические методы в Java принадлежат классу, а не экземпляру. Компилятор разрешает вызов по типу ссылки (Foo), а не по объекту, на который она указывает. На этапе компиляции вызов obj.staticMethod() заменяется на Foo.staticMethod(), поэтому ссылка obj вообще не используется во время выполнения. Это контрастирует с экземплярными методами, где попытка вызова на null действительно приводит к NPE. ✅ Как правильно? Всегда вызывай статические методы через имя класса: Foo.staticMethod(); Это делает код предсказуемым и сразу даёт понять, что метод статический. ⚠️ Нюанс: Даже если метод объявлен как synchronized, вызов через null-ссылку сработает — монитор захватывается у объекта класса, а не у экземпляра. #java #джава #javadeveloper #javatutorial #javaprogramming
Джун помечает приватный метод аннотацией @Transactional и ожидает, что сохранение данных обернётся транзакцией. Но Spring молча игнорирует аннотацию — транзакция не открывается, откаты не работают, а разработчик даже не подозревает об этом. Почему так? Spring управляет транзакциями через AOP-прокси. Когда ты вызываешь метод бина, на самом деле вызывается прокси, который оборачивает вызов в транзакцию. Прокси — это подкласс твоего класса, и он может перехватить только public методы. Private методы недоступны для перехвата ни у JDK-прокси, ни у CGLIB. Поэтому аннотация на них просто не срабатывает. ✅ Как правильно? Сеньор всегда вешает @Transactional на public методы. И помнит, что даже public метод должен вызываться через прокси (из другого бина), а не через this внутри того же класса. ⚠️ Нюанс: Self-invocation (вызов @Transactional метода из другого метода того же класса) тоже не сработает — прокси не увидит вызов. Решение: внедрить self-ссылку (@Autowired private MyService self) или вынести метод в отдельный сервис. #java #джава #javadeveloper #javatutorial #javaprogramming
Двусторонняя очередь, которая заменяет и Queue, и Stack. За 30 секунд объясняю, как она работает и почему ArrayDeque — лучший выбор. #java #джава #javadeveloper #javatutorial #javaprogramming

2просмотра

Ключевое слово для видимости переменной между потоками. За 30 секунд объясняю, как оно работает и почему не спасает от гонки данных. #java #джава #javadeveloper #javatutorial #javaprogramming
Блокировка, которая даёт доступ к коду только одному потоку. За 30 секунд объясняю, как она работает и когда применять. #java #джава #backend #программист #javadev #разработка
Джун ❌ делит без точности и получает ArithmeticException. Сеньор ✅ указывает масштаб и RoundingMode — результат всегда корректен. #java #джава #backend #javadev #bigdecimal #разработка

1просмотр

Java контейнер для значения, которого может не быть. За 20 секунд объясняю, как он спасает от NPE и чем orElse отличается от orElseGet. #java #джава #backend #программист #javadev #разработка
Пробрасываем причину исключения, а получаем NullPointerException. Разбираю ловушку getCause() за 30 секунд, чтобы ты не терял стек ошибок. Смотри до конца, чтобы не наступить в проде. #java #джава #javadeveloper #javadev #javadevelopment

1просмотр

Ленивые вычисления, которые не работают без терминальной операции. За 20 секунд объясняю, как устроен конвейер стримов. Смотри, чтобы не забывать collect. #java #джава #backend #javadev #разработка
Джун ❌ жмёт == и получает false там, где ожидал true. Сеньор ✅ всегда использует equals — сравнивает содержимое, а не ссылки. Смотри за 10 секунд, чтобы не путаться в операторах. #java #джава #backend #javadev #разработка

3просмотра

Потокобезопасная мапа без блокировки всей коллекции. За 20 секунд объясняю, как она работает и чем отличается от HashMap. Смотри, чтобы не ошибиться с выбором. #java #джава #backend #программист #javadev #разработка