Java | Фишки и трюки
7.21K subscribers
182 photos
29 videos
6 files
40 links
Java: примеры кода, интересные фишки и полезные трюки

Купить рекламу: https://telega.in/c/java_tips_and_tricks

✍️По всем вопросам: @Pascal4eg
Download Telegram
🌐 Kubernetes для Java-разработчика — деплой без паники

Когда Java-приложение готово, остаётся один вопрос: а как его запустить в проде?
Если тебе нужен масштаб, отказоустойчивость и автоматизация — ответ один: Kubernetes.
Показываю, как он работает с Java-приложением — без воды 👇

📦 Сборка: сначала контейнер
FROM eclipse-temurin:17
COPY target/app.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

➡️ Сборка стандартная. Главное — получить рабочий Docker image
🟢 Один и тот же образ можно запускать локально и в кластере
🟢 Неважно Spring это, Micronaut или Quarkus — всё сводится к jar + Dockerfile

🟡 Kubernetes Deployment — всё начинается отсюда
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
spec:
replicas: 2
selector:
matchLabels:
app: java-app
template:
metadata:
labels:
app: java-app
spec:
containers:
- name: app
image: myorg/java-app:1.0
ports:
- containerPort: 8080

➡️ Разворачивает несколько копий приложения
🟢 Контейнер запускается в поде, под управлением kubelet
🟢 Один deployment.yaml заменяет тонны bash-скриптов и ручного запуска

🌐 Сделать доступным: Service
apiVersion: v1
kind: Service
metadata:
name: java-service
spec:
selector:
app: java-app
ports:
- port: 80
targetPort: 8080
type: LoadBalancer

➡️ Прокидывает внешний трафик внутрь кластера
🟢 LoadBalancer в облаке, ClusterIP — для внутренней связи
🟢 Без Service приложение живёт, но недоступно

📡 Настройка входа — через Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: java-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: java-service
port:
number: 80


➡️ Публичный домен, HTTPS, маршрутизация — всё через Ingress
🟢 Можно добавить cert-manager для автоматических TLS
🟢 Ingress — как прокси, только встроенный и декларативный

🔁 Обновления без даунтайма
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1

➡️ Kubernetes обновляет поды по очереди
🟢 Пользователи не замечают релиза
🟢 Микросервисы обожают это


🛠 ConfigMap и Secrets — без пересборки образа

apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
SPRING_PROFILES_ACTIVE: prod


envFrom:
- configMapRef:
name: app-config

➡️ Конфиги выносятся из jar-файла
🟢 Смена конфигурации = обновление без пересборки
🟢 Секреты тоже выносятся отдельно — не пиши пароли в YAML

🗣️ Запомни: Kubernetes — как космический корабль. Первый запуск трудный, но потом ты просто говоришь “🚀 в прод”, и всё летит.
Please open Telegram to view this post
VIEW IN TELEGRAM
101👍123🤯1
🐳 Docker Compose для Java: запускаем всё и сразу, в один файл

Когда у тебя Spring Boot, база, очередь и ещё 2 микросервиса — руками это не запустишь.
Docker Compose — способ задеплоить всё одним махом.
Без скриптов, без флагов, без “а где тут Redis?”. Просто up -d — и готово 👇


📦 Минимальный пример — Spring Boot + Postgres
version: '3.9'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/demo
- SPRING_DATASOURCE_USERNAME=java
- SPRING_DATASOURCE_PASSWORD=secret
depends_on:
- db

db:
image: postgres:16
environment:
- POSTGRES_DB=demo
- POSTGRES_USER=java
- POSTGRES_PASSWORD=secret

➡️ Всё в одном файле: и приложение, и база
🟢 depends_on гарантирует порядок запуска
🟢 Не нужен отдельный Postgres — он стартует сам
➡️ Ты просто клонируешь проект и запускаешь — как магия

🔄 Hot reload: монтируем код
volumes:
- .:/app

➡️ Приложение пересобирается при изменениях
🟢 Удобно для разработки, особенно с Spring DevTools
🟢 Работает как live reload, но без веб-сокетов

🧪 Добавляем ещё сервис: например, Redis
  redis:
image: redis:7
ports:
- "6379:6379"

➡️ В Java конфиге указываешь localhost:6379 — и всё
🟢 Redis появляется в сети как обычный контейнер
🟢 В Compose все сервисы в одной сети по умолчанию


🔐 .env для переменных окружения
SPRING_DATASOURCE_USERNAME=java
SPRING_DATASOURCE_PASSWORD=secret


env_file:
- .env

➡️ Хранишь секреты вне Compose-файла
🟢 Удобно для CI/CD
🟢 Никогда не коммить .env в репозиторий

🚫 Остановка и очистка
docker compose down -v

➡️ Останавливает и удаляет тома, сети, контейнеры
🟢 -v — чтобы не остался мусор от базы
🟢 Это не “stop” — это аннигиляция всего стенда

🗣️Запомни: Docker Compose — как мультиварка: закинул всё внутрь, нажал кнопку, через минуту обед.
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍8
⚔️ Kubernetes v🆚 Docker Compose — что выбрать для деплоя Java-приложения

Оба запускают контейнеры.
Оба читают YAML.
Но у одного — кнопка "всё просто", а у второго — масштаб и продакшен.

🐳 Docker Compose: для dev и staging
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
depends_on:
- db
db:
image: postgres:16

➡️ Всё в одном файле, разворачивается за 10 секунд
🟢 Подходит для локальной разработки и тестов
🟢 Никаких ingress, сервисов, namespaces
➡️ Отлично, пока всё помещается в голову

☸️ Kubernetes: для продакшена и масштабов
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
spec:
replicas: 2
template:
spec:
containers:
- name: java
image: myapp:1.0
ports:
- containerPort: 8080

➡️ Управление через pod'ы и deployment'ы
🟢 Поддерживает автоскейлинг, rolling updates, отказоустойчивость
➡️ Требует kubectl, ingress, сервисов, конфигов
🟢 Не подойдёт, если ты просто хочешь “запустить и посмотреть”

📡 Сеть: как доступен сервис

Compose:
ports:
- "8080:8080"

➡️ Пробрасывает порт хоста прямо в контейнер

Kubernetes:
kind: Service
spec:
type: LoadBalancer

➡️ Отдельный объект Service, управление через балансировщик

🟢 Kubernetes — это про маршрутизацию, а не про “форвард порт”

🔐 Переменные и секреты

Compose:
env_file:
- .env

➡️ Подключение переменных из файла

Kubernetes:
envFrom:
- configMapRef:
name: app-config

➡️ConfigMap и Secret — всё разделено по объектам
🟢 В K8s конфигурация живёт отдельно от кода и образа

🔁 Обновления

Compose:
docker compose down && docker compose up -d

➡️ Всё падает и поднимается заново

Kubernetes:
strategy:
type: RollingUpdate

➡️ Плавные обновления без даунтайма
🟢 K8s сам обновляет по одному поду


🗣️ Запомни: Docker Compose — это как запускать Java через main(). Kubernetes — как запускать через продакшеновый оркестр с логами, шинами и охраной.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍32
Media is too big
VIEW IN TELEGRAM
☕️ Переменные и типы данных. Как хранить информацию в приложении.

В этом видео автор объясняет, что такое переменные и типы данных в Java.
Разбирается, как в языке хранится информация, какие бывают типы (int, double, boolean и др.) и как правильно их использовать.


🤩 Java Фишки и трюки || #Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84😇1
👑 API Gateway: единая точка входа для всех запросов

В Java API Gateway — это слой, который принимает все запросы к микросервисам, решает, куда их направить, и что с ними сделать по пути.
Он не выполняет бизнес-логику — он управляет потоком данных и правилами доступа.

📛 Пример: простейший роутинг
public class ApiGateway {
public void handleRequest(String path) {
if (path.startsWith("/users")) {
userService();
} else if (path.startsWith("/orders")) {
orderService();
} else {
notFound();
}
}
void userService() { System.out.println("👥 Обработка пользователей"); }
void orderService() { System.out.println("📦 Обработка заказов"); }
void notFound() { System.out.println(" Маршрут не найден"); }
}

➡️ Один вход — разные направления. Gateway решает, куда отправить запрос.

🧪 Добавляем фильтры и валидацию
public void handleRequest(String path, String token) {
if (!isValidToken(token)) {
System.out.println("⛔️ Доступ запрещён");
return;
}
if (path.startsWith("/admin")) {
adminService();
} else {
publicService();
}
}
boolean isValidToken(String token) {
return token != null && token.equals("secret");
}
void adminService() { System.out.println("🔐 Админ-панель"); }
void publicService() { System.out.println("🌍 Публичный API"); }

➡️ Логика авторизации в одном месте, а не разбросана по сервисам.

🛠 Применение на практике

Смотри, нужно добавить кеширование без изменения кода сервисов:
import java.util.HashMap;
import java.util.Map;

public class CachingGateway {
private Map<String, String> cache = new HashMap<>();

public String handle(String path) {
if (cache.containsKey(path)) {
return "⚡️ Из кеша: " + cache.get(path);
}
String response = callService(path);
cache.put(path, response);
return response;
}

String callService(String path) {
return "Данные для " + path;
}
}

➡️ Сервисы ничего не знают о кешировании — всё делает Gateway.

💾 Другой кейс — агрегация данных
public class AggregationGateway {
public String aggregate() {
String users = getUsers();
String orders = getOrders();
return "👥 " + users + " | 📦 " + orders;
}
String getUsers() { return "5 пользователей"; }
String getOrders() { return "12 заказов"; }
}

➡️ Один запрос к Gateway — и клиент получает объединённые данные из разных сервисов.

📦 Комбинации: безопасность + логирование + роутинг
public class SecureLoggingGateway {
public void handle(String path, String token) {
log(path);
if (!isValidToken(token)) return;
route(path);
}
void log(String path) { System.out.println("📜 Лог: " + path); }
boolean isValidToken(String token) { return "secret".equals(token); }
void route(String path) { System.out.println("➡️ Роутинг к " + path); }
}

➡️ Весь контроль — в одном месте, а не в каждом сервисе.

📚 API Gateway и enum маршрутов
public enum Route {
USERS, ORDERS, STATS
}
public class EnumGateway {
public void dispatch(Route r) {
switch (r) {
case USERS -> System.out.println("👥 Пользователи");
case ORDERS -> System.out.println("📦 Заказы");
case STATS -> System.out.println("📊 Статистика");
}
}
}

➡️ Даже маршруты можно жёстко задать через enum для безопасности.

🗣️ Запомни: API Gateway — это точка, где решается всё: куда пойдёт запрос, кто его выполнит, и что будет по пути. Один слой — и порядок во всей системе.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍143
🧵 Structured Concurrency в Java — управление задачами в одном scope, без утечек и хаоса

Structured Concurrency — это модель, где все задачи живут в одном «контейнере».
Падает одна — падают все. Контейнер закрыт — задачи завершены.

📁 Шаг 1: проблема без структуры
Thread t1 = new Thread(() -> fetchUsers());
Thread t2 = new Thread(() -> fetchOrders());
t1.start(); t2.start();

➡️ Потоки живут сами по себе, ошибки не передаются, ресурсы не контролируются.

📁 Шаг 2: ждём задачи вручную
t1.join();
t2.join();

➡️ Мы можем подождать завершения, но всё ещё нет общей отмены при ошибке.

📁 Шаг 3: общий пул потоков
ExecutorService ex = Executors.newFixedThreadPool(2);
Future<String> f1 = ex.submit(() -> fetchUsers());
Future<String> f2 = ex.submit(() -> fetchOrders());

➡️ Теперь задачи в одном месте, можно управлять ими через Futures.

📁 Шаг 4: обработка ошибок централизованно
try {
String u = f1.get();
String o = f2.get();
} catch (Exception e) {
f1.cancel(true);
f2.cancel(true);
}

➡️ Если одна задача падает — отменяем все остальные.

📁 Шаг 5: таймауты для всех задач
List<Future<String>> results = ex.invokeAll(tasks, 1, TimeUnit.SECONDS);

➡️ Через 1 секунду все незавершённые задачи отменяются.

📁 Шаг 6: try-with-resources для пула
try (ExecutorService ex2 = Executors.newFixedThreadPool(2)) {
// запуск задач
}

➡️ При выходе из блока пул и все задачи закрываются автоматически.

📁 Шаг 7: объединение результатов
String combined = u + " | " + o;
System.out.println(combined);

➡️ Structured Concurrency упрощает сбор данных от разных задач.

📁 Шаг 8: CompletableFuture для асинхронщины
CompletableFuture<String> u = CompletableFuture.supplyAsync(() -> fetchUsers());
CompletableFuture<String> o = CompletableFuture.supplyAsync(() -> fetchOrders());

➡️ Задачи стартуют параллельно, и можно дождаться всех вместе.

📁 Шаг 9: join с обработкой ошибок
CompletableFuture.allOf(u, o).join();

➡️ Ждём обе задачи; если одна упадёт — получим исключение и сможем отменить вторую.

📁 Шаг 10: собственный scope-класс
class TaskScope implements AutoCloseable {
ExecutorService ex = Executors.newCachedThreadPool();
List<Future<?>> futures = new ArrayList<>();
<T> Future<T> fork(Callable<T> c) { var f = ex.submit(c); futures.add(f); return f; }
public void close() { futures.forEach(f -> f.cancel(true)); ex.shutdownNow(); }
}

➡️ Теперь у нас есть контейнер для задач, который сам их отменит при закрытии.

📁 Шаг 11: запуск в scope
try (TaskScope scope = new TaskScope()) {
var f1 = scope.fork(() -> fetchUsers());
var f2 = scope.fork(() -> fetchOrders());
}

➡️ Выйдя из try — все задачи будут остановлены.

📁 Шаг 12: добавляем логику таймаута внутрь scope
Future<T> forkWithTimeout(Callable<T> c, long t, TimeUnit u) {
return ex.submit(() -> ex.submit(c).get(t, u));
}

➡️ Теперь каждая задача в scope может иметь свой лимит времени.

📁 Шаг 13: завершение
System.out.println(" Все задачи завершены в одном месте");

➡️ Structured Concurrency даёт полный контроль над жизнью задач — от запуска до завершения.

🗣️ Запомни: Structured Concurrency — это про контроль и предсказуемость.
Все задачи в одном scope → нет висящих потоков, нет утечек, нет забытых таймаутов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥92
🚀 CI/CD: автоматизация сборки и доставки — и это работает

CI/CD позволяет запускать сборку, тесты и деплой без участия человека.
Но если ты подключаешь CI/CD к проекту — ты отмечаешь его как “готовый к автоматизации”.
Это и есть CI/CD — конвейер, который действует по событиям.

📛 Пример: сборка и тесты в Jenkins
pipeline {
agent any
stages {
stage('Build') { steps { sh 'mvn clean package' } }
stage('Test') { steps { sh 'mvn test' } }
}
}

push в main
➡️ Jenkins не ждёт команды — он сам собирает и проверяет проект.

🧪 Проверка — через GitHub Actions
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
java-version: '17'
- run: mvn clean verify

➡️ Вот где начинается магия: код проверяется сразу при пуше.

🛠 Применение на практике

Смотри, тебе нужно различать коммиты с кодом и релизы.
Не хочешь вручную запускать тесты перед релизом? — решается одной конфигурацией.
on:
push:
tags:
- 'v*'

➡️ Любой тег с версией запустит сборку релиза.

💾 Другой кейс — автоматический деплой
- name: Deploy
run: ssh user@server 'cd /app && git pull && ./restart.sh'

➡️ Без ручного захода на сервер, без копирования файлов — просто push.

📦 Комбинации: проект — это набор этапов
- run: mvn test      # тесты
- run: docker build # сборка контейнера
- run: helm upgrade # деплой в Kubernetes

➡️ Всё описано в сценарии: от проверки до выката.

📚 даже для инфраструктуры
- uses: hashicorp/setup-terraform@v2
- run: terraform apply -auto-approve

➡️ CI/CD может управлять серверами и базами так же, как кодом.

🗣️ Запомни: CI/CD — это не костыль, а чистый, системный способ доставлять код.
Оно не думает, а действует. Всё, что нужно — событие в репозитории.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍103❤‍🔥2
📦 Массивы, строки и коллекции в Java: быстро, гибко, удобно

Java даёт три больших способа хранить данные: массивы (Array), строки (String) и коллекции (ArrayList, HashMap).
Каждый из них — под свой сценарий.

🧩 Массив — фиксированный размер и быстрый доступ
int[] numbers = {1, 2, 3};
System.out.println(numbers[0]); // 1
numbers[1] = 42; // меняем элемент

➡️ Индекс — ключ, размер фиксирован, добавлять новые элементы нельзя без создания нового массива.


📜 Строки — неизменяемые последовательности символов
String text = "Hello";
String upper = text.toUpperCase();
System.out.println(text); // Hello
System.out.println(upper); // HELLO

➡️ String в Java — immutable. Любое «изменение» создаёт новую строку. Для частых правок есть StringBuilder.

📋 ArrayList — динамический список
import java.util.ArrayList;

ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
System.out.println(list.get(1)); // Python
list.remove(0); // удалили "Java"

➡️ Масштабируется сам. Можно добавлять/удалять элементы без забот о размере.


🗺 HashMap — хранение по ключу
import java.util.HashMap;

HashMap<String, Integer> ages = new HashMap<>();
ages.put("Alice", 25);
ages.put("Bob", 30);

System.out.println(ages.get("Bob")); // 30

🟢 Идеально, если нужно быстро искать по ключу, а не по индексу.

🛠 Комбо: коллекции + массивы
ArrayList<int[]> matrix = new ArrayList<>();
matrix.add(new int[]{1, 2, 3});
matrix.add(new int[]{4, 5, 6});
System.out.println(matrix.get(1)[2]); // 6


➡️ Можно вкладывать одно в другое, создавая гибкие структуры данных.


🗣️ Запомни: Выбирай структуры данных по задаче — массивы для скорости и фиксированного размера, StringBuilder для частых изменений строк, ArrayList для гибких списков и HashMap для мгновенного поиска по ключу.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍115👏21
Media is too big
VIEW IN TELEGRAM
☕️Циклы и операторы в них (For, While, Do while)

Это видео посвящено циклам в языке Java — фундаментальной теме для любого разработчика. Ты научишься использовать циклы for, while и do-while, а также освоишь операторы управления потоком внутри циклов.


🤩 Java Фишки и трюки || #Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3
☕️ CI/CD с Jenkins Pipelines — как Java проект летит в прод

Сборка руками? Заливка через FTP?
⛔️ Это не девелопмент, а тетрис в продакшене.

Jenkins автоматизирует всё — от сборки до деплоя, пока ты пьёшь кофе ☕️
Вот как это работает на Java 👇

⚙️ Что такое Jenkins Pipeline

Jenkinsfile — это сценарий, который описывает, что и как делать с кодом.
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './gradlew build'
}
}
stage('Test') {
steps {
sh './gradlew test'
}
}
stage('Deploy') {
steps {
sh 'scp build/libs/app.jar user@server:/app/'
}
}
}
}

🟢 Всё по шагам: сначала билд, потом тесты, потом деплой
➡️ Каждый коммит триггерит этот сценарий

🔥 Плохо без CI/CD:
🟢Костыльные .bat скрипты и ручной scp
🟢Кто-то залил баг — тесты никто не запускал
🟢Ночью прод лег, никто не понял, почему


✔️ Хорошо с Jenkins:
🟢git push → Jenkins билдит и пушит сам
🟢Ошибся в тестах? Не пройдёшь дальше
🟢Всё логируется, откатывается и работает одинаково везде


👍 CI — это контроль. CD — это доставка без боли.

Сборка Java проекта в пайплайне
stage('Build') {
steps {
sh './mvnw package -DskipTests'
}
}

➡️ Jenkins билдит .jar или .war сам
🟢 Поддерживает Gradle, Maven, Ant — что угодно

🧪 Тесты — обязательный рубеж
stage('Test') {
steps {
sh './mvnw test'
}
}

➡️Никаких «ну оно у меня работало»
🟢 Прогон JUnit и Coverage на каждый коммит

🚀 Деплой на сервер — без доступа к ssh
stage('Deploy') {
steps {
sh 'scp target/app.jar user@host:/srv/'
}
}

➡️ Jenkins сам подключается, копирует, рестартит
🟢 Или делает docker build + push → K8s deploy

🗣️ Запомни: CI/CD нужен не когда всё плохо. А чтобы плохо не стало. Jenkins спасёт от багов, усталости и вечного "вручную".
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥65
☕️ ArrayList & HashMap: быстрые коллекции, которые решают всё

В Java массивы — фиксированные, а коллекции умеют расти, менять размер и работать с разными типами данных.
ArrayList и HashMap — два столпа, на которых держатся 80% задач.

🔢. Создание и добавление
import java.util.ArrayList;

ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");

👉 ArrayList хранит элементы в порядке добавления и умеет расти автоматически.

🔢. Доступ по индексу
String lang = list.get(0);
System.out.println(lang); // Java

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

🔢. Перебор элементов
for (String l : list) {
System.out.println(l);
}

👉 Удобный синтаксис for-each для чтения всех значений без возни с индексами.

🔢. HashMap: хранение по ключу
import java.util.HashMap;

HashMap<String, Integer> map = new HashMap<>();
map.put("Apples", 5);
map.put("Oranges", 3);

👉 HashMap — это ключ-значение. Ключи уникальны, значения можно повторять.

🔢. Получение по ключу
int count = map.get("Apples");
System.out.println(count); // 5

👉 Быстрое извлечение: доступ почти моментальный.

🔢. Проверка наличия
if (map.containsKey("Oranges")) {
System.out.println("Есть апельсины!");
}

👉 Нет ключа — вернёт false, а не ошибку.

🗝 🔢. Перебор пар
for (var entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

👉 Легко пройтись сразу и по ключам, и по значениям.


🗣️ Запомни: массивы — это база, но ArrayList и HashMap дают гибкость. Используй массивы, когда важна скорость и фиксированный размер, а коллекции — когда нужно удобно, динамично и без лишней возни.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍115🔥4
Media is too big
VIEW IN TELEGRAM
☕️Условные конструкции (if-else, switch-case)

Это видео объясняет, как работают условные операторы в Java. Ты узнаешь, как с помощью if, else if, else и switch-case принимать решения в коде и управлять логикой программы.


🤩 Java Фишки и трюки || #Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43🔥2
⌨️ Дженерики (generics) — это механизм, который позволяет создавать классы, интерфейсы и методы, работающие с различными типами данных, при этом сохраняя строгую типизацию. Они были введены в Java начиная с версии 5 для повышения безопасности типов и повторного использования кода.

Дженерики позволяют определить параметр типа, который будет заменен конкретным типом данных при создании экземпляра класса или вызове метода. Например, List<T> может использоваться как List<String>, List<Integer> и т.д.

Благодаря дженерикам, ошибки типа (например, попытка вставить объект неправильного типа) обнаруживаются на этапе компиляции, а не во время выполнения программы.

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

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


public class Box<T> {
private T item;

public void setItem(T item) {
this.item = item;
}

public T getItem() {
return item;
}
}

Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
String str = stringBox.getItem();

В этом примере класс Box<T> является обобщенным и может работать с любым типом данных, который заменит T при создании объекта.

#java #generics #T
Please open Telegram to view this post
VIEW IN TELEGRAM
👍165🔥4
⌨️ StringJoiner - это класс, который предназначен для объединения строк с использованием разделителя между ними. Этот класс был введен в Java 8 в пакете java.util. Он облегчает создание текстовых последовательностей, объединяя строки и вставляя разделители между ними.

Вызов метода toString() возвращает объединенную строку с разделителями и окружающими символами.

Вы также можете использовать метод setEmptyValue() для определения значения, которое будет использоваться, если StringJoiner остается пустым.


StringJoiner sj = new StringJoiner(", ", "[" , "]");
sj.setEmptyValue("No items");
System.out.println(sj.toString()); // No items

sj.add("Apple").add("Banana").add("Cherry");
System.out.println(sj.toString()); // [Apple, Banana, Cherry]


#java #StringJoiner
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍9🔥4
☕️Distributed Tracing — Zipkin без боли

Когда у тебя микросервисы, баги превращаются в квест.
Клиент сделал запрос ➡️ прошёл через API ➡️ сервис авторизации ➡️ сервис платежей ➡️ сервис нотификаций.
А потом где-то что-то упало. Где искать?
Логов тонны, grep не спасает.

Тут появляется Zipkin — Sherlock Holmes твоей системы.

📦 Поднять Zipkin проще простого

Через Docker:
docker run -d -p 9411:9411 openzipkin/zipkin

➡️ Открываешь [http://localhost:9411](http://localhost:9411) — готово. У тебя веб-интерфейс для трассировок.

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

Zipkin использует концепцию trace и span:

🟢trace = весь путь запроса от начала до конца
🟢span = отдельный шаг внутри пути (запрос к БД, вызов другого сервиса)

Каждый сервис при вызове следующего передаёт trace-id и span-id в заголовках (обычно X-B3-TraceId, X-B3-SpanId).
➡️ В итоге: в UI ты видишь красивую диаграмму, где висит каждый шаг.

⚙️ Интеграция в Spring Boot

Добавляешь зависимости:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>


А в application.yml:
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0

➡️ Теперь каждый запрос автоматически получает trace-id, а все логи будут содержать [traceId, spanId].

🔍 Пример лога
2025-08-22 12:42:01 [traceId=4af3, spanId=1a2b] Calling PaymentService

➡️ Видишь traceId? Теперь ты можешь в Zipkin найти все вызовы, связанные с этим запросом.

🎯 Зачем это реально нужно

👍 🕵️ Находить медленные места (Bottlenecks)
👍 🐛 Локализовать баг в цепочке сервисов
👍 📊 Смотреть статистику по задержкам и ошибкам


🗣️ Запомни: В микросервисах без трассировки ты как водитель без фар ночью.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍7
⚡️ Reactive Streams в Java — WebFlux + Project Reactor

Когда у тебя миллион запросов и сервер начинает задыхаться — обычный Spring MVC с потоками умирает. Тут выходит на сцену Spring WebFlux и движок Project Reactor. Асинхронщина, backpressure, и код, который реально дышит под нагрузкой.

📦 Подключаем WebFlux в pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

➡️ Всё. Теперь у тебя вместо старого DispatcherServlet — реактивный движок Netty.

🧠 Минимальный контроллер на WebFlux:
@RestController
public class HelloController {
@GetMapping("/hello")
public Mono<String> hello() {
return Mono.just("👋 Привет, реактивный мир!");
}
}

➡️ Mono = 0..1 значение (как Future). Flux = поток значений.

📛 Пример со стримом чисел:
@GetMapping("/numbers")
public Flux<Integer> numbers() {
return Flux.range(1, 5).delayElements(Duration.ofSeconds(1));
}

➡️ Клиент получает числа по одному каждую секунду. Не JSON сразу, а настоящий поток.

🔄 Реактивные операторы (Project Reactor):
Flux.just("A", "B", "C")
.map(s -> s.toLowerCase())
.filter(s -> !s.equals("b"))
.subscribe(System.out::println);

➡️ Конвейер: map → filter → подписка. Реактивщина — это не if’ы и for, а цепочки.

💥 Backpressure — контроль нагрузки:
Flux.interval(Duration.ofMillis(10))
.onBackpressureDrop()
.subscribe(i -> System.out.println("⚡️ " + i));

➡️ Если потребитель не успевает — лишние данные отбрасываются. Ты управляешь потоком, а не он тобой.

🔐 Интеграция с БД через R2DBC:
@Repository
public interface UserRepo extends ReactiveCrudRepository<User, String> {}

@GetMapping("/users")
public Flux<User> getUsers() {
return userRepo.findAll();
}

➡️ Даже база работает реактивно. Никаких блокировок потоков.

Чем отличается WebFlux 🆚 Project Reactor?

👍 Project Reactor = библиотека реактивных стримов (Mono, Flux, операторы).
👍 WebFlux = фреймворк на базе Reactor, чтобы писать контроллеры, API и сервисы.


📚 Документация:
👉 Reactor 👈

👉 WebFlux 👈


🗣️ Запомни: Reactive Streams — это не магия ради хайпа. Это способ выжить под нагрузкой, где обычный синхронный код падает. Если хочешь сервер, который тащит десятки тысяч соединений — без WebFlux и Reactor ты уже динозавр.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥105👍5
Media is too big
VIEW IN TELEGRAM
☕️ Массивы данных. Одномерные и многомерные массивы

В этом видео разбираются основы работы с массивами в Java. Автор показывает, как создавать и использовать одномерные и многомерные массивы, как обращаться к их элементам и перебирать данные. Это базовый инструмент, без которого невозможно работать с большими наборами информации.


🤩 Java Фишки и трюки || #Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍4
🧹 Advanced GC Tuning — ZGC в Java

Если ты думаешь, что GC — это просто «собрал мусор и пошёл дальше», то добро пожаловать в ад продакшена с кучей тредов и 200 ГБ heap’а.
Обычный GC может стопнуть мир на секунду — и твой сервис превращается в «слайдшоу». Для маркетплейса или финтеха — смерть.
Тут на сцену выходит ZGC — сборщик мусора, который обещает паузы меньше 1 мс, даже на огромных хипах.

📦 Как включить ZGC

Запускаешь Java-приложение с флагами:

java -XX:+UseZGC -Xmx16g -Xms16g -jar app.jar

➡️ -XX:+UseZGC активирует Z Garbage Collector.
➡️ Работает начиная с JDK 11 (продакшен-стабил с 15).

🧠 В чём магия ZGC?

Обычный GC работает так: стопнул мир → пересобрал кучу → отпустил.
ZGC же:

🟢 Делает конкурентную маркировку и компактификацию (почти весь GC идёт параллельно с твоим кодом).
🟢 Использует цветные указатели (colored pointers), чтобы отслеживать состояние объектов.
🟢 Работает без длинных стопов — паузы \~0.5–2 мс даже при 100+ ГБ heap.

➡️ Идеален для real-time систем, API с миллионами RPS, финансовых транзакций.

⚙️ Настройки для тюнинга

Базовые:
-XX:+UseZGC
-XX:ZUncommitDelay=300
-XX:SoftMaxHeapSize=12g


🟢 ZUncommitDelay — через сколько секунд освобождать неиспользуемую память (по умолчанию 300).
🟢 SoftMaxHeapSize — мягкий лимит кучи (GC будет стараться держаться в нём, даже если Xmx больше).


Мониторинг:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintGC -Xlog:gc*:gc.log

➡️ Логи GC покажут, как часто идут паузы и сколько памяти реально отжимается.


🔍 Пример GC-лога с ZGC
[2.345s][info][gc,start    ] GC(0) Pause Mark Start
[2.345s][info][gc ] GC(0) Concurrent Mark
[2.348s][info][gc ] GC(0) Pause Mark End 0.2ms
[2.349s][info][gc ] GC(0) Concurrent Relocate

➡️ Видишь? Паузы меньше миллисекунды, всё остальное уходит в concurrent.

Когда брать ZGC, а когда нет

🟢 Бери:

🟢 У тебя огромные хипы (16–500 ГБ).
🟢 Важны низкие latency (игры, трейдинг, API).
🟢 Ты не хочешь тратить дни на ручной тюнинг старых GC.


🔴 Не бери:

🟢Если у тебя микросервис на 512 МБ heap (Overkill).
🟢Если нужен максимальный throughput (G1 иногда быстрее на маленьких heap’ах).


🗣️ Запомни:Он не делает чудес — память всё равно надо оптимизировать, но он гарантирует, что GC-паузы не убьют твой SLA.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍54🔥4👏1
Media is too big
VIEW IN TELEGRAM
☕️ Коллекции в Джава (Collections Framework)

В этом видео автор подробно объясняет, как работает Collections Framework в Java.
Пошагово демонстрируются основные интерфейсы и реализации: List, Set, Map, а также важные классы вроде ArrayList, HashSet, HashMap. Показано, как правильно выбирать подходящую коллекцию, когда использовать список, а когда — отображение, как добавлять, удалять и перебирать элементы.


🤩 Java Фишки и трюки || #Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍3🔥3😁1
⚡️ Reactive Streams: поток вместо цикла — и это работает

В обычном Java-коде всё блокируется: запрос ждёт ответ, поток простаивает.
В реактивщине (Spring WebFlux) — данные текут как река.
Ты подписался на поток → получил элементы по мере готовности.


📛 Пример: возвращаем поток данных
import reactor.core.publisher.Flux;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
@GetMapping("/users")
public Flux<String> getUsers() {
return Flux.just("Alice", "Bob", "Charlie");
}
}

➡️ Не List, а Flux.
Клиент получит поэлементно: Alice → Bob → Charlie.

🔄 Mono vs Flux

👍 Mono<T> → 0..1 элемент
👍 Flux<T> → 0..N элементов
@GetMapping("/user")
public Mono<String> getUser() {
return Mono.just("Alice");
}

➡️ Реактивщина различает одиночный результат и поток.

🧪 Преобразования прямо в цепочке
Flux.range(1, 5)
.map(i -> i * 2)
.filter(i -> i > 5)
.subscribe(System.out::println);

➡️ Поток как коллекция, но лениво и неблокирующе.

📦 Асинхронные запросы
@GetMapping("/external")
public Mono<String> callApi(WebClient client) {
return client.get()
.uri("https://api.example.com/data")
.retrieve()
.bodyToMono(String.class);
}

➡️ Без блокировок. Пока API думает — поток свободен для других задач.

🔗 Комбинация потоков
Mono<String> u1 = Mono.just("Alice");
Mono<String> u2 = Mono.just("Bob");

Flux<String> merged = Flux.merge(u1, u2);

➡️ Потоки объединяются — результат приходит как готов.

👀 Backpressure (контроль скорости)
Publisher шлёт данные → Subscriber сам говорит, сколько готов принять.
Нет перегрузки, система держится даже при большом потоке событий.



🗣️ Запомни: Не блокируйся на ожидании. Подписывайся, фильтруй и трансформируй.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤‍🔥43
ZGC 🆚 Shenandoah — битва без стоп-пауз

Java в 2025 уже умеет два монстра low-latency GC: ZGC и Shenandoah.
Оба обещают микросекундные паузы даже на кучах в сотни гигабайт.
Но у каждого свой характер. Давай разберёмся.

📦 Запуск

ZGC (JDK 15+):
java -XX:+UseZGC -Xmx16g -Xms16g -jar app.jar


Shenandoah (JDK 12+, лучше JDK 17+):
java -XX:+UseShenandoahGC -Xmx16g -Xms16g -jar app.jar


➡️ Оба вкл/выкл одним флагом.

🧠 Архитектура под капотом

🔵 ZGC:

🟢Использует colored pointers (цветные указатели в 64-битных адресах).
🟢Разносит паузы на микросекундные stop-the-world (STW).
🟢Очень простая логика: mark → relocate, всё конкурентно.


🔴 Shenandoah:

🟢Делает concurrent compacting: сжимает кучу без паузы.
🟢Использует brooks pointers (доп. уровень индирекции → каждый объект указывает на forwarder).
🟢Чуть медленнее из-за этой индирекции, но тоже держит паузы \~<10мс.


⚙️ Пример приложения для сравнения
import java.util.ArrayList;
import java.util.List;

public class StressTest {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) {
for (int i = 0; i < 100; i++) {
list.add(new byte[1024 * 1024]); // 100MB
}
if (list.size() > 2000) list.clear(); // держим heap живым
}
}
}


📊 Запускаем и смотрим логи

🔵 ZGC (-XX:+UseZGC -Xlog:gc*):
[2.345s][info][gc] GC(7) Pause Mark Start 0.2ms
[2.345s][info][gc] GC(7) Pause Mark End 0.1ms
[2.346s][info][gc] GC(7) Concurrent Relocate 45.6ms

➡️ Паузы \~0.1–0.3 мс. Основная работа уходит в «Concurrent Relocate», но это в фоне.

🔴 Shenandoah (-XX:+UseShenandoahGC -Xlog:gc*):
[2.456s][info][gc] Pause Init Mark 1.2ms
[2.457s][info][gc] Concurrent Mark 38.9ms
[2.496s][info][gc] Pause Final Evac 1.5ms

➡️ Паузы больше (1–2 мс), но всё ещё очень маленькие.


🧪 Реальные различия (TL;DR)

Характеристика        | ZGC 🟢                       | Shenandoah 🔴
-------------------- | ---------------------------- | ----------------------------
⏱️ Паузы (latency) | ~0.2–2 мс (супер-стабильно) | ~1–10 мс (чуть длиннее)
⚡️ Throughput | Чуть выше (нет индирекции) | Чуть ниже (Brooks ptr)
🗂 Heap size | До 16 ТБ (!) | Ограничен ~4–8 ТБ
🧩 Сложность | Простая модель | Более гибкий, но сложнее
🎯 Подходит для | Trading, real-time API | Крупные JVM-сервисы, где не критичны 2–3 мс



🎯 Выводы

👍 ZGC → если нужна ультра-низкая задержка (финтех, realtime). Работает предсказуемо.
👍 Shenandoah → если heap до пары терабайт и важнее гибкость (много опций тюнинга).

🗣️ Запомни: ZGC = хирург с лазером, точный и быстрый.Shenandoah = механик с инструментами, чуть дольше, но чинит даже сложные ситуации.В продакшене пробуй оба — профит зависит от нагрузки и архитектуры.
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍4🔥4