Перейти к содержимому
Технологии IT обновлён 06.09.2023

Java Books

Java Books — канал о книгах по Java в Telegram. Здесь вы найдёте рекомендации и обзоры книг для программистов разного уровня.

В канале есть книги по основам языка, объектно-ориентированному программированию, многопоточности, сетевому и веб-программированию.

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

Публикации канала

Работаете с файлами в Java? Используйте `Path` и `Files` из NIO.2. Для простого чтения и записи больше не нужны цепочки из FileReader и BufferedReader: Path path = Path.of("notes.txt"); String text = Files.readString(path); Files.writeString(path, "Привет, Java!"); List<String> lines = Files.readAllLines(path); Меньше шаблонного кода, явная работа с путями и UTF-8 по умолчанию у этих методов чтения и записи. Path.of, readString и writeString доступны с Java 11. Для больших файлов используйте потоковое чтение: приведённые методы загружают содержимое целиком.

Открыть в Telegram

Приглашаем на Java Jam — бесплатный митап ЮMoney для бэкенд-разработчиков 🔥 ✅ 29 октября, четверг, 19:00 (мск) — приходите на митап в Санкт-Петербурге или смотрите трансляцию.  Спикеры из ЮMoney и Сбера выступят с докладами: 🟣 Один апгрейд — больше сотни сервисов: как мы обновляем Java-стек в компании Обсудим, как обновить Gradle, Spring Boot и Java в 120+ компонентах, не останавливая разработку. Расскажем, как выстраивали процессы на протяжении этого времени: от порядка действий и массовых патчей до взаимодействия с командами и решения трудностей, с которыми столкнулись во время последнего обновления. 🟣 Как я автоматизировал свой проект — и всё сломал Разберём, как выстроить автоматизацию в проекте с помощью ИИ и какие шишки можно набить на пути. Поговорим, как работает длинный контекст в моделях и как организовать работу с учётом этих особенностей. 🟣 Откатить нельзя оставить: мониторинг выкладки релиза на основе Sentry Ошибки случаются. Узнаем, какие из них появляются или возникают чаще после последнего релиза — и достаточно ли этого, чтобы принять решение об откате. Зарегистрируйтесь, чтобы принять участие. Все подробности — на сайте митапа Java Jam👈

Открыть в Telegram

Java: помогите IDE заметить возможный `NullPointerException` до запуска программы. Аннотации `@NonNull` и `@Nullable` описывают контракт: где null недопустим, а где его нужно обработать. String displayName(@NonNull User user) { @Nullable String name = user.getName(); if (name == null) { return "unknown"; } return name.toUpperCase(); } `user` не должен быть `null`, а имя может отсутствовать – поэтому перед toUpperCase() стоит проверка. При поддержке выбранных аннотаций IDE или статический анализатор предупредит о нарушении контракта прямо во время написания кода. Сами аннотации не гарантируют проверку во время выполнения. Их поведение зависит от библиотеки и инструментов. Чтобы контракт работал между методами, помечайте и параметры, и возвращаемые значения – например, getName().

Открыть в Telegram

Spring Boot запустился быстрее. А обязательная проверка так и не выполнилась. Причиной может быть одна настройка: spring.main.lazy-initialization=true Она откладывает создание многих бинов до момента, когда они понадобятся. Вместе с ними откладывается и `@PostConstruct`. Если внутри такого бина спрятаны прогрев кеша или ваша проверка схемы БД, они выполнятся только при его создании. Никто не запросил бин — код может вообще не запуститься. Другие последствия: первый запрос может стать медленнее, а ошибка конфигурации обнаружится уже после старта приложения. Критическую инициализацию можно оставить на старте: @Component @Lazy(false) public class SchemaVerifier { @PostConstruct void init() { verifySchema(); } private void verifySchema() { // Проверка совместимости схемы БД } } `@PostConstruct` означает «после создания бина», а не «обязательно при запуске приложения». Нюанс: lazy-бин всё же может создаться на старте, если нужен другому бину, который инициализируется сразу. https://docs.spring.io/spring-boot/reference/features/spring-application.html

Открыть в Telegram

💡 Миллион потоков в Java? С virtual threads это реально Виртуальные потоки, ставшие стабильной возможностью в Java 21, позволяют обслуживать множество задач, которые большую часть времени ждут ответа от сети или базы данных. Каждому такому потоку не нужен отдельный поток ОС. При многих блокирующих I/O-операциях JVM освобождает системный поток для другой работы, пока виртуальный ждёт. Код остаётся привычным и последовательным, без обязательного перехода на цепочки колбэков. Особенно полезно для множества одновременных HTTP-запросов и обращений к БД. Но тяжёлые вычисления быстрее не станут: виртуальные потоки помогают увеличить число обслуживаемых задач, а не скорость процессора. И да: миллион потоков не означает миллион соединений с БД. Пулы соединений и ограничения нагрузки по-прежнему нужны.

Открыть в Telegram

🔥 Хочешь быстрее расти в IT? Хватит учиться в одиночку Окружение решает больше, чем кажется. Собрал папки и каналы, где можно быстрее влиться в нужное направление, следить за трендами и не вариться в своём пузыре. AI: t.me/ai_machinelearning_big_data Python: t.me/pythonl Linux: t.me/linuxacademiya Хакинг: t.me/linuxkalii DevOps: t.me/DevOPSitsec Docker: https://t.me/+90Z5TAyfuNU5YmRi Golang: t.me/Golang_google Rust: t.me/rust_code C++: t.me/cpluspluc C#: t.me/csharp_ci Java: t.me/javatg JavaScript: t.me/javascriptv React: t.me/react_tg Frontend: t.me/front PHP: t.me/phpshka Android: t.me/android_its Мобильная разработка: t.me/mobdevelop Базы данных: t.me/sqlhub Data Science: t.me/data_analysis_ml Big Data: t.me/bigdatai Математика: t.me/data_math Физика: t.me/fizmat Kubernetes: t.me/kubernetc GameDev: https://t.me/gamedev Haskell: t.me/haskell_tg Собеседования и карьера: DS собеседования: t.me/machinelearning_interview Python собеседования: t.me/python_job_interview Папка с вакансиями: t.me/addlist/_zyy_jQ_QUsyM2Vi Папка Go разработчика: t.me/addlist/MUtJEeJSxeY2YTFi Папка Python разработчика: t.me/addlist/eEPya-HF6mkxMGIy Папка ML: https://t.me/addlist/2Ls-snqEeytkMDgy Папка Frontend: https://t.me/addlist/mzMMG3RPZhY2M2Iy Полезное сверху: ИТ-мемы: t.me/memes_prog Английский для программистов: t.me/english_forprogrammers ИИ и технологии: t.me/vistehno 954 ГБ open-source курсов: https://t.me/+rKBQEMccAA01MTcy ИТ-книги бесплатно: https://t.me/addlist/BkskQciUW_FhNjEy Max Ai: https://max.ru/ai_machinelearning_big_data Max python: https://max.ru/pythonl ТЕХНО: https://max.ru/vistehno Max Go: https://max.ru/Golang_google Max Linux: https://max.ru/linuxkalii Devops: https://max.ru/DevOPSitsec C#: https://max.ru/csharp_ci C++: https://max.ru/cpluspluc SQL: https://max.ru/sqlhub Java: https://max.ru/javatg Подписывайся на нужные направления и собирай себе ленту, которая реально двигает вперёд.

Открыть в Telegram

💡 Одинаковый ввод? Не вычисляйте результат заново. Сохраняйте результаты затратных вычислений в кэше: ✅ Используйте входные данные как ключ в Map. ✅ Если кэш общий для нескольких потоков, выбирайте ConcurrentHashMap. ✅ computeIfAbsent() вычислит и сохранит значение, если ключа ещё нет. Следующие вызовы вернут готовый результат. Нюанс: если функция вернула null или выбросила исключение, результат не сохранится и вычисление может повториться. Сам по себе ConcurrentHashMap не ограничивает размер кэша и не удаляет устаревшие записи.

Открыть в Telegram

Forwarded From 🧠 Spring AI показал, как сделать RAG заметно умнее обычного vector search. Проблема классического RAG: похожий документ ещё не значит полезный. Новый пайплайн делает так: Question → Rewrite → MultiQuery → Vector Search → Jev Filter → Rerank → LLM Jev проверяет каждый найденный chunk: есть ли там реальный ответ, противоречие или prompt injection. В демо vector search нашёл 6 фрагментов, но до модели дошли только 2 действительно полезных. Меньше мусора в контексте → точнее ответы и меньше шансов на prompt injection. Код и разбор: https://spring.io/blog/2026/10/02/spring-ai-modular-rag-typesafe-jev/

Открыть в Telegram

💡 Предпочитайте делегирование наследованию Связь is-a выглядит удобно: создаём подкласс, наследуем поведение и пишем меньше кода. Но есть цена. ✅ Подкласс получает весь API родителя. ✅ Он зависит от деталей реализации суперкласса. ✅ Изменение родительского класса может неожиданно сломать потомка. И чем глубже иерархия, тем сложнее понять, откуда вообще взялось конкретное поведение. Часто безопаснее композиция: class OrderService { private final PaymentService paymentService; } Вместо наследования: class OrderService extends PaymentService { } Композиция связывает объекты. Наследование связывает их судьбы. Если объекту просто нужна чужая функциональность, чаще лучше её делегировать, а не наследовать.

Открыть в Telegram

Apache Kafka курс 2026: бесплатный курс по Kafka с нуля до профи на русском Kafka обучение без воды: каждый модуль состоит из понятной теории, схем, команд, которые можно запустить у себя, типичных ошибок и вопросов для самопроверки. Курс подходит, чтобы выучить Kafka с нуля, подготовиться к собеседованию на backend, data engineer или DevOps-позицию и спроектировать надёжную систему на Kafka в продакшене. https://github.com/justxor/KAFKAFREECOURSR

Открыть в Telegram

🖥 Java в 2026 году: 25 лучших практических примеров кода от основ до многопоточности https://uproger.com/java-v-2026-godu-25-luchshih-prakticheskih-primerov-koda-ot-osnov-do-mnogopotochnosti/

Открыть в Telegram

☕ Java: в HashSet всего 10 элементов, а обход всё равно тормозит Редкий нюанс: время обхода HashSet зависит от количества элементов и размера внутренней таблицы. var ids = new HashSet<Integer>(1_000_000); for (int i = 0; i < 10; i++) { ids.add(i); } for (int id : ids) { process(id); } После добавления элементов внутри выделена огромная таблица. Итератор проходит по её ячейкам, включая пустые, хотя size() возвращает всего 10. Сложность обхода - O(size + capacity). Поэтому большая ёмкость «про запас» может замедлить регулярный перебор. Если коллекция уже сильно разрослась, а затем почти опустела, можно пересобрать её: ids = new HashSet<>(ids); Новый набор подберёт ёмкость под оставшиеся элементы. Пересборка требует времени и дополнительной памяти, поэтому имеет смысл перед многократными обходами, а не внутри каждого цикла. Документация - https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/HashSet.html

Открыть в Telegram

☕️ Java получил практический MCP-сервер для медицинского AI-триажа На JavaOne показали систему, где жалоба пациента превращается в тикет, а AI определяет его срочность. Теперь Oracle подробно разобрала MCP-сервер, который принимает текст и возвращает оценку от 0 до 10. Сервер построен на Helidon и публикует один инструмент через @Mcp.Tool. Клиенту не нужно знать, какая модель работает внутри. Доступны два режима: * локальный MiniLM через DJL - 384-мерные эмбеддинги, без API и сети; * OpenAI text-embedding-3-small - 1536-мерные эмбеддинги. Финальную оценку в обоих случаях вычисляет локальная нейросеть DeepNetts. Важный нюанс: для каждого типа эмбеддингов нужна отдельно обученная модель оценки. Нельзя взять модель, обученную на векторах MiniLM, и передать ей векторы OpenAI, даже если привести их к одинаковому размеру. MCP-интерфейс при этом остаётся неизменным: жалоба → эмбеддинг → DeepNetts → срочность 0–10 Локальный режим подходит для разработки и интеграционных тестов, внешний - для проверки качества на более мощной модели. https://inside.java/2026/07/25/design-java-mcp-tool/ Inside.java Pairing In-Process and Hosted Embeddings for Java MCP Tool Development - Inside.java Discover why a Java MCP tool can benefit from both in-process and hosted embeddings: in-process embeddings keep development, testing, and conformance fast and reliable, while external provider-backed embeddings offer production-quality semantic scoring behind…

Открыть в Telegram

Apache Kafka 4.x - продвинутый бесплатный практический курс 2026 года https://github.com/justxor/KAFKAFREECOURSR/tree/main

Открыть в Telegram

Autobase Это инструмент, разработанный для автоматизации развёртывания и управления PostgreSQL-кластерами с использованием Ansible. Он поддерживает широкий набор функций, включая настройку репликации, автоматизацию резервного копирования с помощью инструментов, таких как pgBackRest и WAL-G, мониторинг состояния кластеров, а также настройку высокодоступной инфраструктуры (HA). Проект упрощает настройку PostgreSQL и снижает вероятность ошибок, обеспечивая удобные плейбуки для типичных задач. Его можно использовать как для новых установок, так и для работы с существующими конфигурациями. https://github.com/autobase-tech/autobase

Открыть в Telegram

⚡️ «Контейнеры - это просто Linux-процессы» - полезное упрощение, но не совсем правда Обычно контейнер объясняют так: > контейнер = обычный Linux-процесс + namespaces + cgroups Для первого знакомства этого хватает. Но OCI Runtime Spec определяет контейнер шире: это изолированная среда для запуска процессов, а не сам процесс. И Linux-механизмы, только один из вариантов реализации. OCI охватывает не только Linux, но и: - Windows - FreeBSD - Solaris - z/OS - VM-based containers То есть контейнер не обязан быть «процессом в Linux». Важнее то, что среда соответствует контейнерной модели: изоляция, файловая система, ресурсы, lifecycle и правила запуска. Хороший разбор того, что контейнер представляет собой на самом деле: https://labs.iximiuz.com/tutorials/oci-containers-explained

Открыть в Telegram

🔥 Java: subList() может неожиданно удерживать огромный список в памяти Кажется, что: List<Item> small = hugeList.subList(0, 10); hugeList = null; оставит только 10 элементов. Но subList() обычно создаёт представление исходного списка, а не независимую копию. Пока жив small, исходный ArrayList и его внутренний массив тоже могут оставаться в памяти. Если нужна отдельная маленькая коллекция: List<Item> small = new ArrayList<>(hugeList.subList(0, 10)); Особенно неприятный баг в кэшах и долгоживущих объектах: сохраняешь 10 элементов — а в памяти остаются сотни тысяч.

Открыть в Telegram

Java-ловушка: почему `parallelStream()` может замедлить приложение Многие думают: «Есть stream(), добавлю parallelStream() — станет быстрее». Но не всегда. parallelStream() использует общий ForkJoinPool Java: users.parallelStream() .map(this::callExternalApi) .toList(); Если внутри идут HTTP-запросы, SQL или ожидание внешнего сервиса, можно получить обратный эффект: забить общий пул потоков увеличить задержки замедлить другие части приложения parallelStream() хорошо подходит для: ✅ сложных CPU-вычислений ✅ обработки больших коллекций ✅ математических операций Но плохо подходит для: ❌ HTTP ❌ базы данных ❌ файлового I/O ❌ ожидания внешних сервисов Для таких задач лучше использовать отдельный пул: ExecutorService executor = Executors.newFixedThreadPool(20); и контролировать количество параллельных операций. Главное правило: parallelStream() — для вычислений. ExecutorService — для бизнес-логики и внешних вызовов. Код может идеально работать на тестах, но в production внезапно получить проблемы из-за одного parallelStream().

Открыть в Telegram

Полезный Java-совет: Не вызывай parallelStream() просто потому, что данных много. Для коротких операций он легко оказывается медленнее обычного stream(), потому что платишь за разбиение задачи, синхронизацию и работу ForkJoinPool. Особенно неприятно то, что по умолчанию parallelStream() использует общий ForkJoinPool.commonPool(). Если приложение уже нагружает его другими задачами, производительность может внезапно просесть вообще в другом месте. Если параллелизм реально нужен, лучше контролировать executor явно, а не прятать его внутри parallelStream().

Открыть в Telegram

⚡️ Java-приём: не храни метаданные классов в `static Map<Class<?>, ...>` — используй `ClassValue`. Допустим, библиотека кеширует информацию о каждом классе: private static final Map<Class<?>, Metadata> CACHE = new ConcurrentHashMap<>(); На первый взгляд всё нормально. Но в приложениях с динамической загрузкой классов — plugins, application servers, hot reload — такой кеш может удерживать Class, а вместе с ним и его ClassLoader. И получить неприятную утечку памяти. В Java для этого есть малоизвестный ClassValue<T>: private static final ClassValue<Metadata> CACHE = new ClassValue<>() { @Override protected Metadata computeValue(Class<?> type) { return buildMetadata(type); } }; Использование: Metadata metadata = CACHE.get(MyClass.class); Что даёт ClassValue: - ленивое вычисление значения для каждого класса; - thread-safe доступ; - не нужен собственный ConcurrentHashMap; - кеш лучше согласован с жизненным циклом загруженных классов. Особенно полезно для reflection, serializers, ORM, DI-контейнеров и framework-кода, где постоянно кешируются данные по Class<?>. 🔥 Если видишь в библиотеке: static ConcurrentHashMap<Class<?>, ...> стоит хотя бы задать вопрос: а почему здесь не `ClassValue`? #Java #JVM #Backend #Programming

Открыть в Telegram

Комментарии

0

Комментарии пишут вошедшие — так видно, кто автор.

Войти

Комментариев пока нет

Будьте первым, кто расскажет о канале другим.

Пожаловаться на канал

Расскажите, что не так: модератор проверит канал и примет решение. Подпись не нужна, но почту можно оставить — тогда ответим.

Причина Что не так (необязательно) Почта для ответа (необязательно)
Открыть в Telegram