Java: примеры кода, интересные фишки и полезные трюки
Купить рекламу: https://telega.in/c/java_tips_and_tricks
✍️По всем вопросам: @Pascal4eg
Информация о канале обновлена 01.10.2025.
Java: примеры кода, интересные фишки и полезные трюки
Купить рекламу: https://telega.in/c/java_tips_and_tricks
✍️По всем вопросам: @Pascal4eg
Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.windowFixed(2))
.forEach(System.out::println);
➡️ Элементы пакуются по 2 штуки.
Вывод:
[1, 2]
[3, 4]
[5]
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
GatherersumPairs =
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
Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.fold(0, Integer::sum))
.forEach(System.out::println);
➡️ Видим все промежуточные суммы.
Вывод:
1
3
6
10
15
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
👇
⚡️ Запуск в миллисекунды
./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 Monohello() {
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. Лучшие проекты совмещают оба подхода.
Владелец канала не предоставил расширенную статистику, но Вы можете сделать ему запрос на ее получение.
Также Вы можете воспользоваться расширенным поиском и отфильтровать результаты по каналам, которые предоставили расширенную статистику.
Также Вы можете воспользоваться расширенным поиском и отфильтровать результаты по каналам, которые предоставили расширенную статистику.
Подтвердите, что вы не робот
Вы выполнили несколько запросов, и прежде чем продолжить, мы ходим убелиться в том, что они не автоматизированные.