Java Portal | Программирование
12.4K subscribers
1.1K photos
90 videos
36 files
963 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика

Связь: @devmangx

РКН: https://clck.ru/3H4WUg
Download Telegram
Ты правильно используешь коллекции в Java?

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

1. ArrayList

Идеально, когда:

Читаешь много, а пишешь мало.

Доступ к элементам по позиции (get(i)).

Почему? Внутри — массив. Чтение очень быстрое, но вставка или удаление в середине медленные, потому что нужно сдвигать элементы.

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

2. LinkedList

Идеально, когда:

Постоянно добавляешь или удаляешь элементы.

Не нужен прямой доступ к элементу по индексу.

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

Используй для: очередей, буферов или структур, где важен порядок, а не скорость доступа.

3. HashMap

Идеально, когда:

Нужно хранить пары ключ/значение.

Требуется быстрый доступ по ключу (как словарь).

Использует функцию хеширования для быстрого поиска. Если hashCode() реализован плохо, может работать медленно и потреблять больше памяти.

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

Перед оптимизацией спроси себя:

Много читаю и мало пишу? → ArrayList

Часто вставляю/удаляю? → LinkedList

Ищу по ключу? → HashMap

Нет универсально «лучшей» структуры. Есть та, которая подходит под твой способ доступа к данным.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍114
This media is not supported in your browser
VIEW IN TELEGRAM
Gitvizz превращает код в интерактивный граф

Терялся в собственном коде?

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

Посмотреть можно на gitvizz.com

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍4
Что такое String Pool

String Pool → это специальная область памяти внутри heap, где Java хранит строковые литералы.
Главная идея → повторное использование строк и экономия памяти.

Как это работает:

String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2); // true


s1 и s2 указывают на один и тот же объект в String Pool → дубликаты не создаются.

Но если сделать так:

String s3 = new String("Java");
System.out.println(s1 == s3); // false


new String() обходит пул и создаёт новый объект в heap.

Зачем это нужно:
→ Экономит память за счёт переиспользования неизменяемых строк.
→ Повышает производительность при повторных строковых значениях.
→ Безопасно для потоков, потому что строки immutable.

Как заставить строку из heap использовать пул?

Ответ:

s3 = s3.intern();


Метод intern() → добавляет строку в пул и возвращает ссылку на объект из пула.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍95
Топ-20 вопросов по микросервисам для Java-разработчиков

На Java67 вышла подборка самых частых вопросов по микросервисной архитектуре — от отличий монолита до тем вроде Docker, Kubernetes, API Gateway, CQRS и Saga-паттернов.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2🤔1
Сценарный вопрос с реального интервью по Java/Spring Boot:

В контроллере вызывается метод сервиса, помеченный аннотацией @Transactional.
Этот метод не только сохраняет сущность, но и отправляет два письма: одно администратору, другое — пользователю, который сделал запрос.

Класс, отвечающий за отправку почты, помечен аннотацией @Async, но Spring всё равно выполняет его синхронно.
В итоге API обрабатывает запрос целых 12 секунд — очевидно, это неприемлемо.

Вопрос: почему так происходит и как это исправить?

Реальная причина:

Когда используется @Transactional, Spring создаёт прокси для транзакции.
Если внутри этого же контекста вызывается @Async-метод, то Spring не создаёт новый поток — потому что вызов происходит внутри того же прокси.

Иными словами, асинхронный код оказывается «заперт» внутри транзакции.

В результате, коммит в базу ждёт, пока оба письма не будут отправлены.

Как исправить:

Заменить прямой вызов отправки писем на event-publisher подход.

После сохранения запроса просто опубликовать событие, например DemoRequestCreatedEvent.

Асинхронные слушатели (@EventListener + @Async) будут обрабатывать отправку писем вне основной транзакции.

Что получаем:

Транзакция завершается за ~100 мс вместо 12 секунд.

API реагирует почти мгновенно.

Письма всё так же надёжно уходят в фоне.

Использование событий и асинхронных слушателей — не просто красивая архитектурная штука, а реальный способ сделать систему быстрой, масштабируемой и профессиональной.

Дополнительный вопрос:
Кроме событий, какие подходы ты используешь, чтобы отделить транзакционную логику (например, коммит в БД) от побочных эффектов вроде отправки писем или уведомлений?

@Java_Iibrary
👍92
This media is not supported in your browser
VIEW IN TELEGRAM
Хочешь сделать крутой GitHub-профиль?

На этом сайте собраны десятки классных README от разработчиков со всего мира. Можно смотреть код, вдохновляться, подхватывать идеи и оформить свой профиль так, чтобы он реально выделялся.

github.com/zzetao/awesome-github-profile

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍3
В Java есть одно зарезервированное слово, которое многие не замечают — yield.

Оно появилось в Java 13 вместе с switch expressions.

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

Пример:

int day = 2;

String result = switch (day) {
case 1 -> "Понедельник";
case 2 -> {
System.out.println("Обработка...");
yield "Вторник"; // значение, которое возвращается
}
default -> "Другой день";
};


yield — не то же самое, что break:

break просто прерывает выполнение;

yield возвращает значение блока в switch, который используется как выражение.

🌟

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍136
🔍Тестовое собеседование с Java-разработчиком из Мегафон уже завтра

15 октября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.

Как это будет:
📂 Мария Пивоварова, старший разработчик в Мегафон, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Мария будет комментировать каждый ответ респондента, чтобы дать понять, чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Марии

Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.

Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot

Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
Шаг за шагом проектируем сокращатель ссылок

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

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
4
В Spring Boot можно включить «мягкое» завершение приложения, добавив в конфиг строку: "server.shutdown=graceful"

server:
shutdown: graceful

spring:
lifecycle:
timeout-per-shutdown-phase: 20s

# Сервер будет завершать работу корректно
# Он даст до 20 секунд на завершение всех запросов и бинов.


Это помогает избежать типичных проблем при остановке сервиса:

- Активные HTTP-запросы обрываются посреди выполнения
- Транзакции в базе откатываются неожиданно
- Потоки прерываются до завершения работы

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11👀4
6.851 MIT: Продвинутые структуры данных (весна'21)

Этот курс давно был у меня в списке рекомендаций. Разбор темы иерархии памяти там отлично подан в контексте cache-oblivious алгоритмов.

https://courses.csail.mit.edu/6.851/spring21/

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2
Сборщик мусора (Garbage Collector, GC) сильно эволюционировал со временем. Сегодня есть несколько вариантов, и ты можешь выбрать тот, что подходит под твои нужды. Смотри:

- Serial GC (олдскул)

Самый простой и древний.
Один поток, останавливает всё приложение на время очистки памяти.
Подходит для мелких приложений, CLI-инструментов или систем с маленьким heap (пара десятков мегабайт).

- Parallel GC

По сути, тот же Serial, но работает в несколько потоков.
Паузы всё ещё есть, но они короче.
Хорош для batch-задач или сервисов, где короткая остановка не критична.

- G1 GC (Garbage First)

С Java 9 — сборщик по умолчанию.
Делит heap на регионы и чистит только самые “грязные”.
Даёт меньше пауз и предсказуемее поведение.
Оптимальный выбор для большинства продакшен-приложений: Spring, микросервисы и т. д.

- ZGC (Z Garbage Collector)

Паузы меньше 1 мс даже при heap в сотни гигабайт.
Работает почти полностью конкурентно, фактически в реальном времени.
Подходит для систем, которые не могут останавливаться: трейдинг, онлайн-игры, API с высокой доступностью.

- Shenandoah GC

Похож на ZGC, но реализован по-другому (Red Hat).
Тоже стремится к минимальным паузам, отлично чувствует себя на Linux.
Менее популярный, но стабильный вариант.

Что выбрать?

Небольшие приложения → Serial

Batch-процессы → Parallel

Веб-сервисы, микросервисы → G1

Реальное время, критичная задержка → ZGC или Shenandoah

GC уже давно не “та самая штука, что стопит Java”, а гибкий инструмент, который можно подобрать под задачу.
И от этого выбора реально зависит будет твое приложение тормозить… или летать

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍104
Transactions_and_Concurrency_Control.pdf
6.3 MB
Если ты работаешь с Java, очень советую почитать последнее издание “Troubleshooting Java”

В книге куча практических вещей: от лучших практик отладки до логирования, трейсинга, телеметрии, модели памяти Java, предотвращения дедлоков, профайлинга и сэмплинга.

Отличное чтиво, если хочешь реально понимать, что происходит под капотом JVM и как быстро находить проблемы в проде.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8
Может ли статический блок выбросить исключение?


У тебя есть класс, который инициализирует какой-то критически важный статический ресурс внутри статического блока. В процессе инициализации может произойти ошибка, и выбросится исключение. Что произойдет, если исключение будет выброшено из статического инициализатора? Какую ошибку в итоге выбросит JVM, и в каком состоянии останется класс после этого?
Подсказка → Если из статического блока выбрасывается исключение, инициализация класса завершается с ошибкой.

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


Ты создаешь класс DatabaseConnection. В конструкторе происходит попытка установить соединение с базой данных, и если это не удается, выбрасывается SQLException. Что произойдет с памятью, выделенной под объект DatabaseConnection, если конструктор выбросит исключение? Можно ли использовать объект после того, как исключение было выброшено?
Подсказка → Конструкторы могут (и часто должны) выбрасывать исключения, если объект невозможно создать в корректном состоянии.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
Хочешь учить и практиковать SQL без установки ничего на компьютер?

Есть классный ресурс и всё работает прямо в браузере.
Можно создавать базы MySQL и PostgreSQL, писать запросы и сразу видеть результат.

Бесплатно → http://sqlplayground.app

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍82
Почему важно давать хорошие имена в коде?

Потому что большую часть времени мы не пишем код, а читаем его. И одно удачное имя способно объяснить то, что комментарий бы растянул на три строки.

Что решает хорошее имя:

Намерение: expireSession() говорит больше, чем process().
Контекст: calculatePriceWithTax() понятнее, чем просто calculate().
Контракт: isEmpty() (логический результат) и getSize() (число) — разное поведение, и имя это чётко показывает.

Простые, но работающие правила:

Глагол + объект для действий: sendInvoiceEmail().
Ясное существительное для данных: PaymentRequest, CustomerId.
Без тайнописи вроде cfg, mgr, tmp2.
Если логика нетривиальна, пусть имя объясняет “почему”: retryOnRateLimit().

А комментарии не нужны? 🤔

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

когда решение неочевидное;
когда нужна историческая справка или ссылка на ADR.

Главное не использовать комментарии, чтобы объяснять то, что код и так должен рассказывать сам.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍132
Топ-20 техник оптимизации SQL-запросов

1. Индексируй под реальные паттерны запросов (композитные, селективные, covering-индексы), а не просто по числу строк. Следи, чтобы статистика была актуальной.
2. Используй EXISTS для проверки наличия данных; COUNT(*) — только если реально нужен подсчёт.
3. Выбирай конкретные колонки, не пиши SELECT *, чтобы сократить I/O и дать шанс использовать covering-индекс.
4. Пиши sargable-предикаты (которые могут использовать индекс). Медленные коррелированные подзапросы лучше переписать через JOIN или EXISTS.
5. Не лечи ошибки DISTINCT’ом. Исправь логику JOIN и ключи; DISTINCT — только когда реально нужно убрать дубликаты.
6. Фильтруй в WHERE, а HAVING используй только для условий после агрегации.
7. Пиши явные JOIN ... ON, не лепи неявные join’ы через WHERE.
8. Используй keyset pagination вместо OFFSET/LIMIT на больших наборах; для выборки подмножества можно применить TABLESAMPLE (если поддерживается).
9. Предпочитай UNION ALL вместо UNION, если дубликаты допустимы.
10. Заменяй широкие OR на UNION ALL, только если каждая ветка может использовать свой индекс.
11. Тяжёлые запросы запускай вне пиковых часов, при возможности — ограничивай ресурсы или ставь в очередь.
12. Избегай OR в условиях JOIN, можно использовать вычисляемые колонки или UNION ALL, если это позволит использовать индекс.
13. Используй GROUP BY, когда нужны агрегированные строки, и оконные функции — когда нужно видеть строки с агрегатами рядом.
14. Используй временные/derived таблицы, если они реально сокращают работу или добавляют статистику; но помни, что это может заблокировать pushdown-оптимизации.
15. При массовой загрузке данных отключай/удаляй некластерные индексы, вставляй пакетами, потом перестраивай. PK/кластерный индекс можно оставить, если помогает.
16. Используй материализованные представления для редко меняющихся и дорогих агрегатов, продумай их обновление и инвалидацию.
17. Избегай не-sargable сравнений (например, <>) по малоселективным колонкам; лучше перепиши в диапазоны.
18. Минимизируй коррелированные подзапросы на больших выборках, переходи на join’ы или EXISTS.
19. Выбирай INNER или LEFT/RIGHT по смыслу, но помни: INNER JOIN обычно быстрее, если подходит по логике.
20. Кешируй часто повторяющиеся выборки: временные таблицы (на сессию), result cache или материализованные представления с продуманными правилами обновления.

Что такое Query Optimizer

Query Optimizer — это компонент СУБД, который определяет наиболее эффективный способ выполнения SQL-запроса, подбирая оптимальный execution plan.

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

Далее оптимизатор генерирует альтернативные execution plans — разные варианты выполнения одного и того же запроса. В каждом плане задаётся:

- порядок доступа к таблицам
- типы соединений
- способы фильтрации и сортировки

Каждому плану присваивается стоимость — оценка по числу чтений с диска, времени CPU и другим факторам.

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

Узнай больше

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍3
Чтобы сделать API быстрым, нужно получать данные из нескольких микросервисов параллельно. Как это требование влияет на выбор между RestTemplate, WebClient и Feign Client?

RestTemplate: Подходит для простых, блокирующих сценариев — например, в старом Spring MVC-приложении, где нужно сделать вызов к другому сервису и дождаться ответа, прежде чем продолжить выполнение. RestTemplate считается устаревшим, вместо него рекомендуется использовать RestClient.

WebClient: Предпочтительный вариант для высокопроизводительных неблокирующих приложений, например, для API-шлюзов, которым нужно одновременно обращаться к нескольким микросервисам и объединять результаты без блокировки потоков.

Feign Client: Лучше всего подходит для взаимодействия между микросервисами, когда хочется писать чистый, читаемый код на основе интерфейсов, абстрагирующий детали HTTP-запросов.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Javaeros! Они сделали MCP официального Java SDK — так что нам больше не придётся разбираться с древней документацией 💪

github.com/modelcontextprotocol/java-sdk

Рекомендация перед использованием: сначала разберись, что вообще такое MCP - пойми саму концепцию. После этого реализация, независимо от языка, уже вопрос синтаксиса.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
5