ru
Feedback
Java | Фишки и трюки

Java | Фишки и трюки

Открыть в Telegram

Java: примеры кода, интересные фишки и полезные трюки Купить рекламу: https://telega.in/c/java_tips_and_tricks ✍️По всем вопросам: @Pascal4eg Менеджер по рекламе: @shmyzna

Больше
6 954
Подписчики
-724 часа
+117 дней
+830 день
Архив постов
☕️ Создание классов и объектов
В этом видео автор показывает, как в Java создавать собственные классы и объекты. Разбирается структура класса, определение полей и методов, а также процесс создания экземпляров через ключевое слово new. Это практическая основа объектно-ориентированного программирования, без которой невозможно двигаться дальше.
🗣️Запомни: умение создавать классы и объекты — фундамент для понимания всей работы с ООП в Java. 🤩 Java Фишки и трюки || #Видео

🌊 JEP 458: Stream Gatherers в Java 22 Java 22 добавила Gatherers — расширение Stream API, которое позволяет собирать элементы не только привычными map/filter/reduce, а своими кастомными способами. Теперь поток можно «собирать» прямо в процессе, без костылей. 📦 Простая идея Gatherer

Stream.of(1, 2, 3, 4, 5)
    .gather(Gatherers.windowFixed(2))
    .forEach(System.out::println);
➡️ Элементы пакуются по 2 штуки. Вывод:
[1, 2]
[3, 4]
[5]
🔄 Sliding Window — скользящее окно

Stream.of(1, 2, 3, 4, 5)
    .gather(Gatherers.windowSliding(3))
    .forEach(System.out::println);
➡️ Формируются окна по 3 элемента с шагом в 1. Вывод:
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
🗂 Группировка по условию

Stream.of("a", "b", "x", "y", "c", "d")
    .gather(Gatherers.groupUntil(s -> s.equals("x")))
    .forEach(System.out::println);
➡️ Группа закрывается, когда встречается "x". Вывод:
[a, b, x]
[y, c, d]
⚙️ Свой Gatherer

Gatherer<Integer, ?, Integer> sumPairs =
    Gatherer.of(
        () -> new int[1], // state
        (state, e, down) -> {
            state[0] += e;
            if (state[0] >= 10) {
                down.push(state[0]);
                state[0] = 0;
            }
            return true;
        },
        (state, down) -> {}
    );

Stream.of(3, 4, 5, 6, 7)
    .gather(sumPairs)
    .forEach(System.out::println);
➡️ Числа суммируются, пока не превысят 10, потом сбрасываются.

12
13
📊 Gatherers.fold — промежуточная агрегация

Stream.of(1, 2, 3, 4, 5)
    .gather(Gatherers.fold(0, Integer::sum))
    .forEach(System.out::println);
➡️ Видим все промежуточные суммы. Вывод:
1
3
6
10
15
⚖️ Gatherers 🆚 Collectors
Collectors работают в конце стрима (collect(...)). Gatherers же действуют прямо в процессе, шаг за шагом.
➡️ Это позволяет писать stateful-преобразования, которые раньше выглядели громоздко. 🚀 Реальные применения
1. Буферизация при работе с большими потоками. 2. Batch-загрузки в БД. 3. Скользящие средние и метрики. 4. Stateful-пайплайны без ручного кода.
➡️ Всё это теперь можно писать нативно в Stream API. 🔗 Комбинации

Stream.of(1, 2, 3, 4, 5, 6)
    .gather(Gatherers.windowFixed(2))
    .map(list -> list.stream().mapToInt(i -> i).sum())
    .forEach(System.out::println);
➡️ Сначала разбиваем на пары, потом суммируем каждую. Вывод:
3
7
11
🗣️ Запомни: Gatherers в Java 22 выводят стримы на новый уровень. Они позволяют обрабатывать данные «на лету» и строить stateful-пайплайны, которые раньше были невозможны без костылей.

⌨️ Как вырасти до Мидла или Синьора в два раза быстрее? 👨‍💻Просто хорошо работать работу не достаточно. Ты делаешь то, что
⌨️ Как вырасти до Мидла или Синьора в два раза быстрее? 👨‍💻Просто хорошо работать работу не достаточно. Ты делаешь то, что нужно компании, а не то, что повысит твой грейд Лучший способ вырасти — это персональный план развития от Senior-инженера из БигТеха. Вот как все работает: 1️⃣ Мок-интервью 1-на-1: Час реалистичного собеса с Senior-инженером из Иннотеха, Сбера или другого бигтеха 2️⃣ Честный фидбек: созвонимся и расскажем твои точки роста, оценим грейд и потенциальный уровень зарплаты 3️⃣Персональный план развития: не просто «учите алгосы», а роадмап с конкретными темами, который приведет тебя к желаемому грейду или офферу. Пример плана развития прикрепили к сообщению Мы в ШОРТКАТ провели уже почти 1000 таких мок-интервью и получили оценку 4.9/5, поэтому знаем о чем говорим. 📈 Да, и все это за 900 рублей. Почему так дешево? Мы хотим, чтобы у каждого была возможность проверить в деле наш сервис, а потом уже доверить нам свое развитие. Переходи в нашего бота и забирай свой мок за 900 рублей @shortcut_sh_bot Реклама. О рекламодателе.

🚀 Spring Boot 3 + AOT компиляция — реальная производительность Spring Boot 3 принёс AOT (Ahead-Of-Time) компиляцию. Теперь можно собирать приложение в нативный бинарь через GraalVM и запускать его почти мгновенно. Это не просто оптимизация — это новый уровень для микросервисов. Разберём, что это даёт в реальных проектах 👇 ⚡️ Запуск в миллисекунды
./mvnw -Pnative native:compile
./target/demo
➡️ Обычный Spring Boot на JVM стартует 2–5 секунд. AOT-бинарь поднимается за 30–50 мс. Это критично для serverless и микросервисов, где холодный старт решает. 📦 Минимальные Docker-образы
FROM ghcr.io/graalvm/native-image:latest as builder
WORKDIR /app
COPY . .
RUN ./mvnw -Pnative native:compile

FROM ubuntu:22.04
COPY --from=builder /app/target/demo /demo
CMD ["/demo"]
➡️ В Docker-контейнере не нужна JVM. Итоговый образ весит 30–50 MB вместо 300–400 MB. 🧠 Экономия памяти
JVM-приложение:     150–200 MB RAM  
AOT-приложение:      20–40 MB RAM  
➡️ GraalVM вырезает неиспользуемые классы, рефлексию и динамику. Сервер держит десятки сервисов вместо пары. 🔗 Поддержка Spring Boot Native
@SpringBootApplication
public class DemoApp {
    public static void main(String[] args) {
        SpringApplication.run(DemoApp.class, args);
    }
}
➡️ Код не меняется. Но при сборке Spring генерирует hint'ы (reflect-config.json), чтобы GraalVM понял, какие классы реально нужны. 🧩 Работа с рефлексией и прокси
@TypeHint(types = {MyEntity.class}, access = AccessBits.ALL)
public class MyHints implements NativeConfiguration {}
➡️ В AOT режиме всё статично. Если библиотека лезет через Class.forName(), нужно явно подсказать GraalVM. Иначе приложение упадёт. ⚙️ Async, WebFlux, Security — всё работает
@GetMapping("/hello")
public Mono<String> hello() {
    return Mono.just("Привет из AOT!");
}
➡️ Reactive-приложения и Spring Security совместимы. Но стоит проверить на совместимость сторонние библиотеки — они не всегда поддерживают AOT. 📊 JIT vs AOT: производительность под нагрузкой
🟢 JIT (обычная JVM) быстрее на долгих задачах, потому что оптимизирует байткод во время работы. 🟢 AOT быстрее стартует и экономнее в памяти, но чуть медленнее на горячем коде.
➡️ Для микросервисов и API важнее быстрый старт и лёгкость. Для больших вычислений — JVM. 🔁 CI/CD и DevOps
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: ./mvnw -Pnative native:compile
      - uses: actions/upload-artifact@v3
        with:
          name: demo-binary
          path: target/demo
➡️ AOT встраивается в pipeline. Сборка дольше (5–10 минут), но итоговый бинарь быстрый и лёгкий. 🚨 Ограничения AOT
👍 Долгая компиляция (в разы медленнее, чем обычный mvn package). 👍 Динамические фреймворки (Hibernate proxies, некоторые reflection API) требуют ручных hint'ов. 👍 Не всегда легко дебажить — стек-трейсы короче.
➡️ Но в продакшене эти минусы окупаются. 🗣️ Запомни: AOT в Spring Boot 3 — это не замена JVM, а выбор под задачу. Если важен холодный старт, размер образа и память — используй AOT. Если нужен гибкий код с динамикой и быстрые билды — оставляй JVM. Лучшие проекты совмещают оба подхода.

☕️Конструкторы класса
В этом видео автор объясняет, что такое конструкторы в Java и зачем они нужны. Пошагово показывается, как создавать конструкторы, передавать параметры при инициализации объектов и использовать перегрузку для разных вариантов создания экземпляров класса.
🗣️Запомни: конструкторы упрощают инициализацию объектов и делают код более удобным и читаемым. 🤩 Java Фишки и трюки || #Видео

⌨️ Почему 1==1 это true, а 128==128 это false?

Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false

Integer x = 1;
Integer y = 1;
System.out.println(x == y); // true
Это не просто волшебство! Это связано с целочисленным кэшированием в Java. Для значений в диапазоне от -128 до 127 объекты типа Integer кэшируются, и ссылки на них одинаковы, а для значений за пределами этого диапазона создаются новые объекты, и ссылки на них будут разными. Так как используется оператор ==, то сравниваются ссылки на объекты. #java #magic

Нижний Новгород, намечается что-то классное 11 октября в вашем городе пройдет Сезон кода — ИТ-фест для тех, кто пишет код, де
Нижний Новгород, намечается что-то классное 11 октября в вашем городе пройдет Сезон кода — ИТ-фест для тех, кто пишет код, держит прод и не боится сложных задач. Соберем инженерное комьюнити города и выкатим осень на прод. В программе фестиваля: — доклады про надежность, масштабирование, перформанс, интеграции, инциденты и практики, которые реально работают; — демо продуктов группы Т-Технологии — заглянем под капот инженерных решений и узнаем, как все устроено; — карьерные консультации с HR-специалистами, которые расскажут, как расти в ИТ. И, конечно, живое общение, активности от инженеров и тусовка с кавер-группой в конце дня. Фест пройдет в культурном центре «Академия Маяк». Успейте зарегистрироваться до 10 октября: https://vk.cc/cPyEgV?/erid=2W5zFGgDWhn

🚀 Project Loom: виртуальные потоки вместо тяжёлых тредов Java всегда славилась многопоточкой, но классические треды прожорливы: на каждый создаётся отдельный системный поток. Loom это меняет — теперь у нас есть виртуальные потоки (virtual threads). 🧵 Старый способ — тяжёлые треды

Thread thread = new Thread(() -> {
    System.out.println("Hello from thread!");
});
thread.start();
➡️ Потоки живут в ОС. Их немного, и каждый ест память и ресурсы. ⚡️ Новый способ — виртуальные потоки

Thread vThread = Thread.ofVirtual().start(() -> {
    System.out.println("Hello from virtual thread!");
});
➡️ Здесь поток лёгкий. Java сама маппит тысячи виртуальных потоков на несколько системных. 🔄 Масштаб без боли

for (int i = 0; i < 1_000_000; i++) {
    Thread.ofVirtual().start(() -> work());
}
➡️ Миллион потоков без OutOfMemoryError. На обычных тредах — краш. ⏸️ Блокировка без страха

Thread.ofVirtual().start(() -> {
    Thread.sleep(1000); // блокируемся
    System.out.println("Done!");
});
➡️ Виртуальные треды спокойно блокируются. JVM паркует их, освобождая ресурсы. 🌐 Асинхронщина без Future/CompletableFuture

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> fetchFromApi());
    executor.submit(() -> readFromDb());
}
➡️ Каждая задача — в своём виртуальном треде. Асинхронность пишется синхронно. 🔧 Работа с I/O

Files.lines(Path.of("data.txt"))
     .forEach(line -> System.out.println(line));
➡️ Даже блокирующее I/O больше не страшно. В Loom оно «кажется» блокирующим, но реально не тормозит. 📊 Где использовать
🟢 сетевые сервисы (много коннектов); 🟢 микросервисы; 🟢 парсеры/скрейперы; 🟢 всё, где тысячи одновременных задач.
🗣️ Запомни: Про «тредпулы и колбэки» скоро можно будет забыть.

🔍Тестовое собеседование с Java-разработчиком из МТС уже завтра 17 сентября(уже завтра!) в 19:00 по мск приходи онлайн на отк
🔍Тестовое собеседование с Java-разработчиком из МТС уже завтра 17 сентября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Илья Аров, старший разработчик в МТС, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Илья будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Илье Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. О рекламодателе.

⌨️ Приведение типов. Понижение и повышение типа Java является строго типизированным языком программирования, а это означает, то что каждое выражение и каждая переменная имеет строго определенный тип уже на момент компиляции. Однако определен механизм приведения типов (casting) - способ преобразования значения переменной одного типа в значение другого типа. В Java существуют несколько разновидностей приведения: ✔️ Тождественное (identity). Преобразование выражения любого типа к точно такому же типу всегда допустимо и происходит автоматически. ✔️ Расширение (повышение, upcasting) примитивного типа (widening primitive). Означает, что осуществляется переход от менее емкого типа к более ёмкому. Например, от типа byte (длина 1 байт) к типу int (длина 4 байта). Такие преобразование безопасны в том смысле, что новый тип всегда гарантировано вмещает в себя все данные, которые хранились в старом типе и таким образом не происходит потери данных. Этот тип приведения всегда допустим и происходит автоматически. ✔️ Сужение (понижение, downcasting) примитивного типа (narrowing primitive). Означает, что переход осуществляется от более емкого типа к менее емкому. При таком преобразовании есть риск потерять данные. Например, если число типа int было больше 127, то при приведении его к byte значения битов старше восьмого будут потеряны. В Java такое преобразование должно совершаться явным образом, при этом все старшие биты, не умещающиеся в новом типе, просто отбрасываются - никакого округления или других действий для получения более корректного результата не производится. ✔️ Расширение объектного типа (widening reference). Означает неявное восходящее приведение типов или переход от более конкретного типа к менее конкретному, т.е. переход от потомка к предку. Разрешено всегда и происходит автоматически. ✔️ Сужение объектного типа (narrowing reference). Означает нисходящее приведение, то есть приведение от предка к потомку (подтипу). Возможно только если исходная переменная является подтипом приводимого типа. При несоответствии типов в момент выполнения выбрасывается исключение ClassCastException. Требует явного указания типа. ✔️ Преобразование к строке (to String). Любой тип может быть приведен к строке, т.е. к экземпляру класса String. ✔️ Запрещенные преобразования (forbidden). Не все приведения между произвольными типами допустимы. Например, к запрещенным преобразованиям относятся приведения от любого ссылочного типа к примитивному и наоборот (кроме преобразования к строке). Кроме того, невозможно привести друг к другу классы, находящиеся на разных ветвях дерева наследования и т.п. При приведении ссылочных типов с самим объектом ничего не происходит, - меняется лишь тип ссылки, через которую происходит обращение к объекту. Для проверки возможности приведения нужно воспользоваться оператором instanceof:

Parent parent = new Child();
if (parent instanceof Child) {
    Child child = (Child) parent;
}
#java #casting #upcasting #downcasting

Ты опытный Java-разработчик. Что дальше? Дальше — искать новые пути развития и обмениваться знаниями. Это можно сделать на Jo
Ты опытный Java-разработчик. Что дальше? Дальше — искать новые пути развития и обмениваться знаниями. Это можно сделать на Joker — крупнейшей Java-конференции в России. 📍 17–18 октября, Санкт-Петербург Тебя ждут хардкорные доклады о современных практиках Java-разработки, новых фичах Java, нюансах Spring, работе JVM под капотом, Kotlin и Scala, ORM и о базах данных. Еще там будут обсуждать архитектуру и backend, нагрузки и производительность, DevOps — выбирай, что ближе по духу.  Помимо докладов будут дискуссии со спикерами, зоны нетворкинга, а в конце первого дня — вечеринка! Подробности и билеты — на сайте Joker. С промокодом JF10 персональный билет стоит дешевле.  Реклама. ООО "ДЖУГ РУ ГРУП". ИНН 7801341446.

⌨️ Что такое default методы интрефейса? Java 8 позволяет добавлять неабстрактные реализации методов в интерфейс, используя ключевое слово default:

interface Example {
    int process(int a);
    default void show() {
        System.out.println("default show()");
    }
}
✔️Если класс реализует интерфейс, он может, но не обязан, реализовать методы по-умолчанию, уже реализованные в интерфейсе. Класс наследует реализацию по умолчанию. ✔️Если некий класс реализует несколько интерфейсов, которые имеют одинаковый метод по умолчанию, то класс должен реализовать метод с совпадающей сигнатурой самостоятельно. Ситуация аналогична, если один интерфейс имеет метод по умолчанию, а в другом этот же метод является абстрактным - никакой реализации по умолчанию классом не наследуется. ✔️Метод по умолчанию не может переопределить метод класса java.lang.Object. ✔️Помогают реализовывать интерфейсы без страха нарушить работу других классов. ✔️Позволяют избежать создания служебных классов, так как все необходимые методы могут быть представлены в самих интерфейсах. ✔️Дают свободу классам выбрать метод, который нужно переопределить. ✔️Одной из основных причин внедрения методов по умолчанию является возможность коллекций в Java 8 использовать лямбда-выражения. Вызывать default метод интерфейса в реализующем этот интерфейс классе можно используя ключевое слово super вместе с именем интерфейса:

interface Paper {
    default void show() {
        System.out.println("default show()");
    }
}

class Licence implements Paper {
    public void show() {
        Paper.super.show();
    }
}

☕️Функции в языке Java
В этом видео автор подробно разбирает, как создавать и использовать функции (методы) в Java. Пошагово объясняется, как объявлять методы, передавать параметры, возвращать значения и вызывать их из других частей программы.
🤩 Java Фишки и трюки || #Видео

🏗 Java Module System (JPMS) — модульность приложения С Java 9 появилась модульная система (JPMS), которая помогает разделять проект на независимые блоки и жёстко контролировать зависимости. Это шаг дальше от обычных JAR-файлов и классического classpath. 📦 Создание модуля через module-info.java
module com.example.app {
    requires com.example.service;
    exports com.example.app.api;
}
➡️ Файл module-info.java лежит в корне src/com.example.app и описывает, какие модули нужны (requires) и какие пакеты доступны наружу (exports). Всё остальное скрыто. 🔒 Инкапсуляция пакетов
module com.example.service {
    exports com.example.service.api;
    // внутренние классы не экспортируются
}
➡️Код внутри модуля по умолчанию недоступен извне. Это защита от случайного использования «внутренних» API. 🔗 Транзитивные зависимости
module com.example.web {
    requires transitive com.example.service;
}
➡️ Если модуль A требует B как transitive, то любой, кто подключает A, автоматически получает доступ к B. 🧩 Пример: приложение из трёх модулей
com.example.model   → только данные
com.example.service → бизнес-логика
com.example.app     → точка входа
➡️ Модули явно описывают связи. Код не сможет обратиться к тому, что не экспортировано. ⚠️ Ошибка при неправильной зависимости
module com.example.model {
    // ничего не экспортирует
}

module com.example.app {
    requires com.example.model;
}
➡️ Компилятор выдаст ошибку: package ... is not visible. Нужно явно exports. 🚦 Сравнение с классическим classpath
👍 classpath: всё видно всем, легко словить «spaghetti» зависимостей. 👍 modules: строгие границы, меньше сюрпризов при рефакторинге.
🔧 Совместимость и migration
🔴 Старые JAR можно подключать через automatic modules. 🔴 Постепенно можно переносить проект на полноценные модули.
🗣️ Запомни: JPMS — это не только про разбиение проекта, но и про контроль связей. Модули делают систему чище, безопаснее и помогают строить большие приложения без хаоса зависимостей.

Роадмап подготовки к Java собеседованиям Цель роадмапа – предоставить список тем и источников для быстрой подготовки к собесе
Роадмап подготовки к Java собеседованиям Цель роадмапа – предоставить список тем и источников для быстрой подготовки к собеседованиям. Темы: – Java (архитектура jvm, gc, многопоточность) – Spring (aop, transaction, cloud) – SQL/NoSQL (acid, base, уровни изоляций, explain) – Kafka/Docker/Kubernetes – Паттерны проектирования, ООП, SOLID – Алгоритмы и структуры данных – Системный дизайн Полная версия роадмапа со всеми темами и источниками лежит в канале @backend_interviewer

🛠 Memory-mapped Files — работа с файлами через ByteBuffer Обычно мы читаем и пишем файлы через стандартные IO-потоки. Но у этого подхода есть потолок скорости. Memory-mapped files позволяют работать с файлами напрямую через память, минуя часть «лишних движений». 📂 Простое чтение через FileChannel
try (FileChannel channel = FileChannel.open(Path.of("data.txt"), StandardOpenOption.READ)) {
    MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
    while (buffer.hasRemaining()) {
        System.out.print((char) buffer.get());
    }
}
➡️ Файл как будто целиком «подмонтирован» в память, а чтение идёт напрямую через ByteBuffer. 💾 Запись в файл
try (FileChannel channel = FileChannel.open(Path.of("out.txt"),
        StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
    MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
    buffer.put("Hello world!".getBytes());
}
➡️ Любые изменения в буфере автоматически попадают в файл. Работа с очень большими файлами
long size = 10L * 1024 * 1024 * 1024; // 10 GB
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
➡️ Даже огромные файлы можно обрабатывать кусками, без полного чтения в память. 🔄 Двусторонний доступ
buffer.put(0, (byte) 'X');
System.out.println((char) buffer.get(0));
➡️ Одно и то же отображение позволяет и читать, и писать данные на месте. 🧱 Ограничения
Memory-mapped файлы зависят от ОС и архитектуры. Если закончилась виртуальная память — программа рухнет.
➡️ Нужно аккуратно выбирать размер отображения и закрывать ресурсы. 🧵 Использование в многопоточке
// Несколько потоков читают один и тот же MappedByteBuffer
➡️ Общая память = быстрый обмен, но придётся синхронизировать доступ. 🗣️ Запомни:Memory-mapped files — это способ работать с файлами так, будто они часть оперативки. Он даёт скорость и гибкость, но требует аккуратного контроля памяти и синхронизации.

Стойте! Если хотите шарить, или уже шарите в Java или Kotlin, то эти каналы однозначно для вас! После их прочтения вы 100% по
Стойте! Если хотите шарить, или уже шарите в Java или Kotlin, то эти каналы однозначно для вас! После их прочтения вы 100% повысите свой уровень в несколько раз! Админ каналов Senior-разработчик, а значит ему можно доверять своё обучение: 1. Java Библиотека — Книги, статьи, фичи и советы. Сборная солянка для прогеров. 2. Kotlin Developer - самый топовый канал для котлин разработчика! 3. Книги для Java Программистов — Название говорит само за себя. Лучшие платные и бесплатные книги собраны в одном месте! 4. Java Guru — Хотите пройти собеседование и рубить по 300.000₽ в месяц? Всё возможно, но для этого надо прорешать не одну сотню задач и тестов — на этом канале как раз всё собрано. 5. Java News — А этот канал ежедневно вводит в курс дела и новостей любимого ЯП! Подписывайтесь на все 5 каналов и станьте мега-программистом!

🔄 CompletableFuture + ExecutorService — сложные асинхронные цепочки Java даёт мощный инструмент для работы с асинхронностью без сторонних библиотек — CompletableFuture вместе с ExecutorService. С их помощью можно строить цепочки вычислений, обрабатывать ошибки и настраивать таймауты. ⚡️ Запуск асинхронной задачи
ExecutorService executor = Executors.newFixedThreadPool(4);

CompletableFuture<String> future =
    CompletableFuture.supplyAsync(() -> {
        sleep(500);
        return "Результат";
    }, executor);

System.out.println(future.join()); // блокируемся и получаем результат
executor.shutdown();
➡️ supplyAsync запускает задачу в отдельном потоке из пула. 🔗 Построение цепочек
CompletableFuture<Integer> chain =
    CompletableFuture.supplyAsync(() -> 10)
        .thenApply(x -> x * 2)
        .thenApply(x -> x + 5);

System.out.println(chain.join()); // 25
➡️ Каждая операция обрабатывает результат предыдущей. Код становится декларативным. 🚦 Обработка ошибок
CompletableFuture<String> safe =
    CompletableFuture.supplyAsync(() -> {
        if (true) throw new RuntimeException("Ошибка");
        return "OK";
    }).exceptionally(ex -> "Fallback");

System.out.println(safe.join()); // Fallback
➡️ exceptionally позволяет задать запасной путь при сбое. ⏱️ Таймауты
CompletableFuture<String> future =
    CompletableFuture.supplyAsync(() -> {
        sleep(2000);
        return "Долго";
    });

String result = future.orTimeout(1, TimeUnit.SECONDS)
                      .exceptionally(ex -> "Таймаут")
                      .join();

System.out.println(result); // Таймаут
➡️ orTimeout прерывает выполнение, если задача не завершилась за указанное время. 🔀 Запуск нескольких задач
CompletableFuture<Integer> a = CompletableFuture.supplyAsync(() -> 1);
CompletableFuture<Integer> b = CompletableFuture.supplyAsync(() -> 2);

CompletableFuture<Integer> sum =
    a.thenCombine(b, Integer::sum);

System.out.println(sum.join()); // 3
➡️ thenCombine позволяет объединять результаты из разных потоков. 🎭 AnyOf и AllOf
CompletableFuture<Object> any =
    CompletableFuture.anyOf(a, b);

CompletableFuture<Void> all =
    CompletableFuture.allOf(a, b);
➡️ anyOf завершится, когда готов хотя бы один, allOf — когда готовы все. 🧩 ExecutorService как фундамент
Важно передавать свой ExecutorService в supplyAsync и runAsync. Иначе будет использоваться общий ForkJoinPool, который не всегда предсказуем.
🗣️ Запомни: CompletableFuture + ExecutorService дают асинхронность, цепочки и контроль ошибок прямо из коробки. Умение строить такие цепи позволяет писать быстрые и надёжные сервисы без Reactive или сторонних решений.

Гайд для маркетологов по эффективным онлайн-встречам Как CMO, PR и digital-маркетологам повысить результативность брейнштормо
Гайд для маркетологов по эффективным онлайн-встречам Как CMO, PR и digital-маркетологам повысить результативность брейнштормов, совещаний и планерок с командой с помощью онлайн-встреч? Гайд МТС Линк: 37 страниц полезных материалов, чек-листов и кейсов для эффективных видеовстреч и совещаний. ✅ В гайде: - Как создать постоянную ссылку на регулярные встречи с подрядчиками, командой или агентствами и подключаться в 2 клика; - Как управлять встречей и завершить ее четкими договоренностями с ИИ-расшифровкой голоса в текст; - Как проводить кастдевы, брейнштормы и формулировать гипотезы с помощью 15+ шаблонов в онлайн-досках МТС Линк; - Как разом пригласить всех участников на синк таким образом, чтобы все пришли. Бонус внутри: 5 способов не выгореть от бесконечных синков. ✨ Скачайте гайд бесплатно по ссылке Скачать #реклама 16+ mts-link.ru О рекламодателе