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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⚡️ Panama API + MemorySegment — работа с off-heap памятью без Unsafe

Когда нужен прямой доступ к памяти без Unsafe и JNI — помогает Panama API.
MemorySegment и MemorySession позволяют работать с off-heap памятью безопасно, быстро и управляемо.

📦 Выделение памяти вне heap
try (var session = MemorySession.openConfined()) {
MemorySegment segment = MemorySegment.allocateNative(100, session);
System.out.println("Размер: " + segment.byteSize());
}

➡️ Память выделяется за пределами JVM heap, но управляется сессией.

🔗 Запись и чтение примитивов
try (var session = MemorySession.openConfined()) {
MemorySegment seg = MemorySegment.allocateNative(8, session);
seg.set(ValueLayout.JAVA_INT, 0, 42);
int x = seg.get(ValueLayout.JAVA_INT, 0);
System.out.println(x);
}

➡️ Читаем и пишем напрямую, как в массив, только в off-heap памяти.

⚡️ Работа с массивами
try (var session = MemorySession.openConfined()) {
MemorySegment seg = MemorySegment.allocateNative(4 * 5, session);
for (int i = 0; i < 5; i++) {
seg.setAtIndex(ValueLayout.JAVA_INT, i, i * 10);
}
System.out.println(seg.getAtIndex(ValueLayout.JAVA_INT, 3));
}

➡️ setAtIndex и getAtIndex делают сегмент похожим на массив.

🌀 MemorySession = контроль жизни

MemorySegment seg;
try (var session = MemorySession.openConfined()) {
seg = MemorySegment.allocateNative(16, session);
}
System.out.println(seg.isAlive()); // false

➡️ После закрытия сессии память освобождается, сегмент становится "мертвым".

📑 Slice и view памяти
try (var session = MemorySession.openConfined()) {
MemorySegment seg = MemorySegment.allocateNative(16, session);
MemorySegment part = seg.asSlice(4, 8);
System.out.println("Slice: " + part.byteSize());
}

➡️ Можно создавать "представления" (slice) на часть памяти.

🚀 Обмен с native-кодом
try (var session = MemorySession.openConfined()) {
MemorySegment seg = MemorySegment.allocateNative(4, session);
seg.set(ValueLayout.JAVA_INT, 0, 123);
long addr = seg.address();
System.out.println("Адрес: " + addr);
}

➡️ Сегмент даёт доступ к "сырому" адресу для интеграции с нативными API.

🗣️ Запомни: Off-heap ускоряет работу с большими данными и нативным кодом без GC overhead.
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍54🤔1
🛡 Java Flight Recorder + JFR Events API — профилирование прямо в коде

Обычно JFR включают флагами JVM, но начиная с Java 14 появился Events API. Теперь можно описывать и логировать свои события прямо из кода, без тяжёлых логгеров.

📦 Определение кастомного события
import jdk.jfr.Event;
import jdk.jfr.Label;

class LoginEvent extends Event {
@Label("User")
String username;

@Label("Success")
boolean success;
}

➡️ Наследуем Event и описываем поля — это как лог-сообщение, но встроенное в JVM.

🚀 Публикация события
LoginEvent e = new LoginEvent();
e.username = "ivan";
e.success = true;
e.commit();

➡️ commit() записывает событие в JFR-файл, который потом анализируется в Mission Control.

🖥 Запуск записи профиля
java -XX:StartFlightRecording=filename=recording.jfr,duration=20s -jar app.jar

➡️ Даже без кода можно собрать JFR-трассу, но с Events API появляются свои бизнес-события.

📊 Использование категорий
import jdk.jfr.Category;

@Category("Auth")
class LoginEvent extends Event {
String username;
}

➡️События группируются в категории, и в Mission Control они будут выделены как отдельный блок.

⚡️ События с таймингом
class CalcEvent extends Event {}

CalcEvent e = new CalcEvent();
e.begin();
// тяжёлая операция
e.end();
e.commit();

➡️ begin()/end() автоматически меряют длительность и пишут её в метрику.

🔗 Комбинация JFR с логами
LoginEvent e = new LoginEvent();
e.username = "alex";
e.success = false;
e.commit();

System.out.println("Login attempt failed: alex");

➡️ Лог для человека, JFR-событие для анализа и графиков — два уровня контроля.

🧩 Интеграция с потоками
class TaskEvent extends Event {
String thread;
}

TaskEvent e = new TaskEvent();
e.thread = Thread.currentThread().getName();
e.commit();

➡️Можно писать, какие потоки нагружают систему и когда они стартуют.

📑 Анализ в Mission Control
Открываешь recording.jfr — и видишь всё: GC, потоки, задержки и свои кастомные события.

🗣️ Запомни: JFR Events API — это быстрый встроенный профайлинг. Свои события почти не грузят систему, пишутся дешевле логов и помогают находить проблемы прямо в продакшене.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41
📦 Records 🆚 Sealed Classes — компактность и контроль

Record убирает шаблонный код и делает объект иммутабельным.
Sealed Class закрывает иерархию и контролирует наследование.
Разные задачи, но вместе решают боль старой Java.


🧩 Record вместо POJO

public record User(String name, int age) {}

➡️ Всё сгенерировано: геттеры, equals, hashCode, toString.
Лаконичность, минимум шаблонов.
Изменять поля нельзя.

📜 Класс вручную vs record

class User {
private final String name;
private final int age;

public User(String name, int age) {
this.name = name;
this.age = age;
}

public String name() { return name; }
public int age() { return age; }
}

➡️ Один record = десяток строк кода.

⚙️ Record с валидацией

public record Product(String name, int price) {
public Product {
if (price < 0) throw new IllegalArgumentException("price < 0");
}
}

➡️ Можно добавлять логику в compact-конструкторе.

🔒 Sealed Class: ограниченная иерархия

public sealed class Shape permits Circle, Rectangle {}

public final class Circle extends Shape {}
public final class Rectangle extends Shape {}

➡️ Никто не добавит новый Shape без изменения sealed-класса.

🎯 Record внутри sealed

public sealed interface Payment
permits CardPayment, CashPayment {}

public record CardPayment(String number) implements Payment {}
public record CashPayment(double amount) implements Payment {}

➡️ Удобное комбо: варианты — records, интерфейс — sealed.

🔎 Pattern Matching по sealed

Payment p = new CardPayment("1234");

switch (p) {
case CardPayment c -> System.out.println("💳 " + c.number());
case CashPayment c -> System.out.println("💵 " + c.amount());
}

➡️ Компилятор гарантирует, что обработаны все варианты.

📐 Sealed vs enum

sealed interface Command permits Reboot, Shutdown {}

record Reboot() implements Command {}
record Shutdown() implements Command {}

➡️ Как enum, но гибче: каждая ветка со своей структурой.

🧮 Комбинации records + sealed

sealed interface Event permits Login, Logout {}

record Login(String user) implements Event {}
record Logout(String user) implements Event {}


➡️ Модель событий простая, неизменяемая и закрытая.

🗣️Запомни:Record = компактный неизменяемый объект вместо шаблонного класса. Sealed Class = закрытая иерархия и контроль наследников.Вместе дают лаконичность и безопасность, снимая боль старой Java.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍5🔥3
⌨️ Что такое текстовые блоки (Text Blocks)?

Text Blocks (""") позволяют удобно работать с многострочными строками без необходимости экранировать кавычки.

Улучшают читаемость кода.
Поддерживают форматирование и перенос строк.
Упрощают работу с JSON, SQL и HTML.

✔️ Пример:


String json = """
{
"name": "Alice",
"age": 30
}
""";

System.out.println(json);


💡 Совет: Используйте Text Blocks для удобного написания больших строковых данных.

#java #textblocks #java15
Please open Telegram to view this post
VIEW IN TELEGRAM
👍103🔥3
⚡️ Scoped Values в Java — альтернатива ThreadLocal для виртуальных потоков

С появлением виртуальных потоков (Project Loom) старый ThreadLocal стал проблемой. Он держит данные на весь поток, что для миллионов lightweight-тредов дорого. Решение — ScopedValue.

📦 Объявление значения
import java.lang.ScopedValue;

public class Demo {
static final ScopedValue<String> USER = ScopedValue.newInstance();
}

➡️ Создаём "контейнер" для данных, которые будут жить только в заданной области.

🧩 Передача значения в scope
ScopedValue.where(USER, "Alice").run(() -> {
System.out.println("Hello, " + USER.get());
});

➡️ Значение доступно только внутри run(). Вышел из scope — данных нет.

⚡️ Виртуальные потоки + ScopedValue
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() ->
ScopedValue.where(USER, "Bob").run(() -> {
System.out.println("User in virtual thread: " + USER.get());
})
);
}

➡️ Локальные данные для каждого виртуального потока без утечек.

🔍 Сравнение с ThreadLocal
ThreadLocal<String> local = new ThreadLocal<>();
local.set("Alice");

➡️ Удобно, но значение живёт, пока жив поток. Виртуальные потоки → миллионы копий → утечки памяти.

🛡ScopedValue — иммутабельность
ScopedValue.where(USER, "Charlie").run(() -> {
// USER.set("Dave"); нельзя
System.out.println(USER.get());
});

➡️ Нельзя изменить внутри scope. Значение задаётся один раз, это делает код безопаснее.

🧠 Наследование scope
ScopedValue.where(USER, "Admin").run(() -> {
new Thread(() -> System.out.println(USER.get())).start();
});

➡️ Новый поток не видит значение. Данные строго локальны. Нет "магического" наследования, как у InheritableThreadLocal.


📊 Где применять
🟢 Контекст запроса (user id, trace id).
🟢 Логирование.
🟢 Передача настроек без проброса аргументов.


Минусы ScopedValue
🔴 Только read-only.
🔴 Живёт только в рамках scope.
🔴 Работает начиная с Java 20+.



🗣 Запомни: ThreadLocal опасен для виртуальных потоков — утечки и лишняя память. ScopedValue проще: задаёшь значение в scope, читаешь только там. Без наследования, без мутабельности, идеально для миллионов lightweight-тредов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍63
🧩 Java без JNI: как FFM API ломает старые правила

Раньше, чтобы вызвать C-код из Java, приходилось страдать с JNI — заголовки, javah, System.loadLibrary(), краши и боль.Теперь всё проще: Foreign Function & Memory API (FFM) — новый стандарт для прямого доступа к нативным функциям и памяти.

⚙️ Импорт C-функций напрямую
FFM API позволяет вызывать функции из libc без JNI.
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;

try (Arena arena = Arena.openConfined()) {
Linker linker = Linker.nativeLinker();
SymbolLookup libc = linker.defaultLookup();
MethodHandle printf = linker.downcallHandle(
libc.find("printf").get(),
FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS)
);
MemorySegment msg = arena.allocateUtf8String("Hello from C!\n");
printf.invoke(msg);
}

➡️ Всё чисто на Java: без генерации C-кода, без jni.h, с полным контролем памяти.

🧠 Работа с нативной памятью
try (Arena arena = Arena.openConfined()) {
MemorySegment segment = arena.allocate(4);
segment.set(ValueLayout.JAVA_INT, 0, 1337);
System.out.println(segment.get(ValueLayout.JAVA_INT, 0));
}

➡️ Создаёшь участок памяти, читаешь и пишешь — без Unsafe и без GC-хаоса.

🧬 Interop с существующими C-библиотеками

Хочешь вызвать strlen или qsort? Пожалуйста.
MethodHandle strlen = linker.downcallHandle(
libc.find("strlen").get(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
);
long len = (long) strlen.invoke(arena.allocateUtf8String("PyLinux"));
System.out.println(len);

➡️ Вызываешь функции C напрямую, как будто они твои.

🧰 Безопасность и контроль
FFM API чётко ограничивает область памяти (через Arena), предотвращая утечки и use-after-free.
Можно использовать “scoped memory” — живёт ровно столько, сколько нужно.


🚀 Производительность
JNI требует перехода между Java и C стэками → дорого.
FFM API компилируется JIT’ом и оптимизируется HotSpot → почти нативная скорость.


🔬 Статический биндинг с jextract

jextract генерирует Java-обёртки по .h-файлам.
jextract -t com.libc /usr/include/stdio.h

➡️ Автоматически создаёт Java-интерфейсы для вызова C-функций — без ручного JNI.

🧱 Будущее без JNI
С FFM API Java получает настоящий доступ к низкоуровневому миру:
🟢 без C-кода,
🟢 без падений JVM,
🟢 без плясок с System.load().


🗣️ Запомни:FFM API — это чистый Java-интерфейс к нативному миру. JNI уходит в прошлое.
Скорость и контроль — без риска.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍7🔥6👎1🥰1
🔥 «Когда поток — это архитектура»
Kafka Streams и ksqlDB + Java: живые системы на событиях


Сервисы больше не должны “ждать запрос”. Современные системы реагируют на события — в реальном времени. Kafka Streams и ksqlDB превращают поток данных в ядро приложения, а не просто транспорт сообщений.

⚡️ 1. Архитектура event-driven

Kafka — это не просто очередь. Это commit-log всех событий в компании:
🟠пользователь оплатил заказ,
🟠склад обновил остатки,
🟠ML-модель прислала прогноз.

➡️Java-сервис подписывается на эти события и сам становится реактивным узлом.


🧩 2. Kafka Streams — логика прямо в потоке

Пример: считаем количество заказов в минуту по пользователю 👇
StreamsBuilder builder = new StreamsBuilder();

KStream<String, String> orders = builder.stream("orders");

orders.groupByKey()
.windowedBy(TimeWindows.of(Duration.ofMinutes(1)))
.count()
.toStream()
.to("orders_per_minute");

KafkaStreams streams = new KafkaStreams(builder.build(), props);
streams.start();

➡️ Данные не хранятся — они *текут*. Поток сам агрегирует и публикует результат в новый топик.

📊 3. KTable и состояние

Kafka Streams позволяет хранить состояние между событиями:
KTable<String, Long> orderCounts = orders
.groupByKey()
.count(Materialized.as("orders-store"));

➡️ KTable — как материализованная view в БД, но в оперативной памяти и постоянно обновляется.

🧠 4. ksqlDB — SQL для стримов

Если не хочется писать Java-код, можно просто запросить поток SQL-ом:
CREATE STREAM orders_stream (user_id VARCHAR, price DOUBLE)
WITH (KAFKA_TOPIC='orders', VALUE_FORMAT='JSON');

CREATE TABLE user_revenue AS
SELECT user_id, SUM(price) AS total
FROM orders_stream
WINDOW TUMBLING (SIZE 1 HOUR)
GROUP BY user_id;

➡️ Результат — новый поток данных. Kafka сама всё поддерживает в актуальном состоянии.

🔄 5. Реактивные микросервисы

Сервисы больше не ходят в БД, чтобы “узнать новое”.
Kafka — это их канал событий.

@KafkaListener(topics = "user_revenue")
public void handleRevenue(String msg) {
System.out.println("💰 " + msg);
}

➡️ Микросервисы реагируют на новые сообщения, а не крутят cron.

🧰 6. Пример конвейера событий
[orders] → [Kafka Streams: агрегация] → [ksqlDB: фильтрация] → [billing-service]

➡️ Каждый шаг — отдельная логика. Данные текут без REST-запросов.

🔗 7. Масштабирование и отказоустойчивость
Kafka Streams хранит state в RocksDB и реплицирует его между инстансами.
Перезапуск — и поток сам продолжает с последнего offset.

➡️ Никакой ручной синхронизации или блокировок.

⚙️ 8. Интеграция с экосистемой Spring
@EnableKafkaStreams
@Configuration
public class StreamConfig {
@Bean
public KStream<String, String> kStream(StreamsBuilder builder) {
return builder.stream("orders");
}
}

➡️ Spring Boot 3 поддерживает Kafka Streams из коробки — никаких костылей.

🚀 9. Kafka как data backbone
Kafka связывает микросервисы, ML, ETL и аналитические пайплайны.
Хранилище, транспорт и очередь — всё в одном.


🧩 10. Когда ksqlDB против Streams
| Сценарий                      | Что выбрать      |
| ----------------------------- | ---------------- |
| Быстрый прототип, SQL-запросы | ksqlDB |
| Сложная логика, типизация | Kafka Streams |
| Обработка JSON и Avro | оба поддерживают |
| Глубокая интеграция с Java | Streams |


🗣️ Запомни:Event-driven — не мода, а способ думать в реальном времени. Kafka Streams — это код, который живёт в потоке данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43🔥3👏1
🛰 «Смотри глубже: Observability в действии»
Мониторинг, трассировка и метрики, которые спасают прод

Observability — это не просто графики и алерты. Это способ понять, что реально происходит внутри системы.
В отличие от обычного мониторинга, observability показывает почему всё пошло не так.


Разберём, как инженеры держат прод под контролем 👇

📡 Metrics — сердце наблюдаемости
Prometheus + Grafana — золотой стандарт.
# prometheus.yml
scrape_configs:
- job_name: 'app'
static_configs:
- targets: ['app:8080']

➡️ Метрики — это числа: latency, CPU, RPS, ошибки.
Grafana визуализирует, Prometheus хранит и алертит.

🧭 Logs — что реально произошло
Elastic Stack или Loki от Grafana.
docker run -d -p 9200:9200 elasticsearch
docker run -d -p 5601:5601 kibana

➡️ Логи нужны, когда метрика показала «плохо».
Хочешь знать, почему? Иди в логи.

🚦 Traces — кто виноват в задержках
OpenTelemetry + Jaeger показывают путь запроса через микросервисы.
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("db_query"):
query_database()

➡️ Trace — это маршрут.
С его помощью видно, где реально теряется время.


🧩 OpenTelemetry — единый язык наблюдаемости
Собирает метрики, логи и трассировки из любого кода.
pip install opentelemetry-sdk opentelemetry-exporter-otlp

➡️ Универсальный стандарт. Работает и с Python, и с Java, и с Go.

💡 Alerting — чтобы не узнавать о сбоях из Telegram
Prometheus + Alertmanager → уведомления при SLA-фейле.
- alert: HighErrorRate
expr: rate(http_requests_total{status="500"}[5m]) > 0.05
for: 2m
labels:
severity: critical

➡️ Хороший alert не просто орёт. Он помогает понять причину.


🧱 Distributed Context — связать всё вместе
Код → метрики → логи → трассы — одно пространство событий.
Zipkin, Tempo, Jaeger — строят полную цепочку от запроса до ответа.

➡️ Это основа SRE-практик: найти проблему за минуты, а не часы.

🔍 Instrumentation — чтобы код умел говорить
Библиотеки сами шлют метрики: Spring Boot Actuator, FastAPI middleware, Django signals.

➡️ Observability — не внешний тул, а часть приложения.

⚙️ Cloud-native observability
AWS CloudWatch, GCP Operations Suite, Datadog, New Relic.
Для Kubernetes — Lens, K9s, Grafana Tempo.


➡️ Современные пайплайны включают observability как часть CI/CD.

🗣 Запомни: Observability ≠ просто мониторинг — это понимание поведения системы.
Please open Telegram to view this post
VIEW IN TELEGRAM
3🔥3👍2
🤝 «Контракты не лгут: как сервисы общаются без боли»
Contract Testing в Java — контроль реальности между продами

Когда микросервисы множатся, интеграционные тесты превращаются в хаос.
Сервис А ждёт одно, сервис B отдаёт другое — и привет, баг в проде.
Contract Testing решает это через договор: что именно API обещает и возвращает.


📄 Суть контракта
Потребитель (Consumer) описывает, что он ждёт от поставщика (Provider).
Provider подтверждает: «Да, я действительно так отвечаю».

➡️ Это проверка не по коду, а по взаимному соглашению.


⚙️ Pact — главный игрок в Java
Pact позволяет Consumer’у описывать ожидаемые запросы и ответы:
@Pact(consumer = "OrderService")
public RequestResponsePact createPact(PactDslWithProvider builder) {
return builder
.given("User exists")
.uponReceiving("a request for user details")
.path("/users/123")
.method("GET")
.willRespondWith()
.status(200)
.body("{\"id\":123,\"name\":\"Alex\"}")
.toPact();
}

➡️ Это «контракт»: JSON с ожиданиями клиента.

🧪 Consumer Test — проверка ожиданий
@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(providerName = "UserService", port = "8080")
public void testUserService(MockServer server) {
Response response = get(server.getUrl() + "/users/123");
assertEquals(200, response.getStatusCode());
}

➡️ Тест проверяет, что клиент правильно формирует запрос и обрабатывает ответ.

🏭 Provider Test — подтверждение контракта
Поставщик поднимает mock и проверяет:
«Я реально возвращаю то, что обещал в контракте».
@Provider("UserService")
@PactFolder("pacts")
class UserServicePactTest {
@TestTarget
final Target target = new HttpTarget(8080);

@State("User exists")
public void userExists() {
// фикстуры для теста
}
}

➡️ Если что-то не совпадает — билд падает.

🔗 Pact Broker — центр доверия
Все контракты хранятся в брокере.
Каждый сервис знает, с кем и что согласовано.
docker run -d -p 9292:9292 pactfoundation/pact-broker

➡️ Это реестр соглашений между микросервисами.

🧩 Contract Testing ≠ интеграция
Интеграционные тесты требуют запущенные сервисы.
Контрактные тесты — только спецификации.

➡️ Меньше зависимостей, быстрее CI, больше стабильности.

🚀 Spring Cloud Contract — альтернатива Pact
Работает прямо в Spring Boot.
contract {
request {
method 'GET'
url '/users/123'
}
response {
status 200
body(id: 123, name: "Alex")
}
}

➡️ Контракт → автогенерированный тест для Provider’а.

Плюсы:
Нет неожиданностей при релизах.
CI ломается до продакшена, если кто-то нарушил контракт.
Каждый сервис тестируется изолированно.


Минусы:minu
Нужно поддерживать актуальность контрактов.
При множестве сервисов — много файлов.
Не ловит ошибки логики (только интерфейсов).


🗣 Запомни: Contract Testing — это «юридическая проверка» между сервисами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍64🔥3
Media is too big
VIEW IN TELEGRAM
☕️Наследование в классах

В этом видео автор подробно объясняет концепцию наследования в Java: как один класс может наследовать свойства и методы другого, когда применять `extends`, как переопределять методы и использовать ключевое слово `super`.


🗣️Запомни: наследование — мощный механизм для повторного использования кода и организации иерархий классов.

🤩 Java Фишки и трюки || #Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
4🔥3
Media is too big
VIEW IN TELEGRAM
☕️Полиморфизм в ООП

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


🗣️Запомни: полиморфизм даёт гибкость в архитектуре и делает код расширяемым и масштабируемым.

🤩 Java Фишки и трюки || #Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
3❤‍🔥2
☕️ Java в потоке данных: Flink, Beam и Spark без магии

Когда данные бегут нескончаемым потоком, а твой монолит не успевает считать, Java превращается в машину для real-time-аналитики.
Flink, Beam и Spark — три пути к масштабным потоковым системам. Ни теории — только код.


💀 Обычный подход — всё тормозит
List<String> lines = Files.readAllLines(Paths.get("data.txt"));
Map<String, Long> counts = lines.stream()
.flatMap(line -> Arrays.stream(line.split(" ")))
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
System.out.println(counts);

➡️ Всё в память, всё синхронно. Умер на первом гигабайте.

⚙️ Flink — потоковые вычисления без задержек
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<String> stream = env.socketTextStream("localhost", 9999);

stream
.flatMap((String line, Collector<String> out) -> {
for (String word : line.split(" ")) out.collect(word);
})
.keyBy(word -> word)
.sum(1)
.print();

env.execute("Flink WordCount");

Реактивная обработка, fault tolerance и state — всё из коробки.

🧩 Spark Structured Streaming — SQL на лету

SparkSession spark = SparkSession.builder().appName("StreamSQL").getOrCreate();

Dataset<Row> lines = spark.readStream()
.format("socket")
.option("host", "localhost")
.option("port", 9999)
.load();

Dataset<Row> words = lines.as(Encoders.STRING())
.flatMap((FlatMapFunction<String, String>) x -> Arrays.asList(x.split(" ")).iterator(), Encoders.STRING());

words.groupBy("value").count()
.writeStream()
.outputMode("complete")
.format("console")
.start()
.awaitTermination();

DataFrame API + реальное время. SQL-запросы к стримам — это норма.

🧠 Beam — пиши один раз, запускай где угодно
Pipeline p = Pipeline.create();
p.apply(TextIO.read().from("input.txt"))
.apply(ParDo.of(new DoFn<String, String>() {
@ProcessElement
public void processElement(ProcessContext c) {
for (String word : c.element().split(" ")) c.output(word);
}
}))
.apply(Count.perElement())
.apply(TextIO.write().to("output"));
p.run().waitUntilFinish();

Beam абстрагирует всё: один pipeline может жить на Flink, Spark, Dataflow — без правок кода.

🚀 Kafka + Flink = real-time пайплайн
FlinkKafkaConsumer<String> consumer = new FlinkKafkaConsumer<>("logs", new SimpleStringSchema(), props);
env.addSource(consumer)
.map(line -> line.toUpperCase())
.addSink(new FlinkKafkaProducer<>("processed", new SimpleStringSchema(), props));

Поток заходит из Kafka, проходит трансформацию и возвращается обратно.

📊 Stateful обработка
stream.keyBy(value -> value)
.flatMap(new RichFlatMapFunction<String, Tuple2<String, Integer>>() {
private transient ValueState<Integer> count;
public void open(Configuration parameters) {
count = getRuntimeContext().getState(new ValueStateDescriptor<>("count", Integer.class));
}
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
Integer current = count.value() == null ? 0 : count.value();
count.update(current + 1);
out.collect(Tuple2.of(value, current + 1));
}
});

Flink хранит состояние между событиями — perfect для realtime аналитики.

🧩 Beam с Cloud Dataflow
PipelineOptions options = PipelineOptionsFactory.create();
options.as(DataflowPipelineOptions.class).setRunner(DataflowRunner.class);

Запускаешь тот же код в Google Cloud — нативно масштабируется.

💡 Spark + Kafka integration
Dataset<Row> df = spark.readStream()
.format("kafka")
.option("kafka.bootstrap.servers", "localhost:9092")
.option("subscribe", "topic")
.load();

Spark сам читает Kafka topics и обрабатывает потоки.

🗣 Запомни: Flink — мозг real-time систем, Spark — мотор аналитики, Beam — мост между ними. Главное — не выбирай фреймворк по моде, выбирай под поток.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥53❤‍🔥2👍1
⌨️ Виды классов

1. Обычные классы (Regular Classes)
Это наиболее распространенные классы, которые вы создаете для определения объектов. Они могут содержать поля, методы, конструкторы и вложенные классы.

public class MyClass {
private int field;

public MyClass(int field) {
this.field = field;
}

public void method() {
// some code
}
}


2. Абстрактные классы (Abstract Classes)
Абстрактные классы не могут быть созданы как объекты напрямую. Они предназначены для предоставления общей функциональности, которую подклассы должны реализовать или дополнить.

public abstract class AbstractClass {
public abstract void abstractMethod();

public void concreteMethod() {
// some code
}
}


3. Вложенные классы (Nested Classes)
Классы, объявленные внутри другого класса. Они могут быть статическими или нестатическими.

🔹 Статические вложенные классы (Static Nested Classes):
Эти классы могут быть созданы без экземпляра внешнего класса.

public class OuterClass {
static class StaticNestedClass {
// some code
}
}


🔹 Внутренние классы (Inner Classes):
Эти классы имеют доступ ко всем членам внешнего класса и создаются в контексте экземпляра внешнего класса.

public class OuterClass {
class InnerClass {
// some code
}
}


4. Локальные классы (Local Classes)
Классы, объявленные внутри метода, конструктора или блока. Они имеют доступ к финальным переменным из охватывающего метода.

public class OuterClass {
public void method() {
class LocalClass {
// some code
}
LocalClass local = new LocalClass();
}
}


5. Анонимные классы (Anonymous Classes)
Классы без имени, создаваемые на месте для реализации интерфейса или наследования от класса. Часто используются для создания экземпляров интерфейсов или абстрактных классов.

public class OuterClass {
public void method() {
Runnable runnable = new Runnable() {
@Override
public void run() {
// some code
}
};
}
}


6. Перечисления (Enums)
Специальные классы, представляющие набор констант. Они могут содержать поля, методы и конструкторы.

public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}


7. Интерфейсы (Interfaces)
Технически не классы, но важная часть объектно-ориентированного программирования в Java. Интерфейсы определяют контракты, которые должны быть реализованы классами.

public interface MyInterface {
void myMethod();
}


8. Записи (Records)
Нововведение в Java 14 (в предварительном виде) и официально в Java 16. Они предоставляют компактный способ создания неизменяемых классов с полями и автоматически сгенерированными методами, такими как equals, hashCode и toString.

public record Point(int x, int y) {}


#java #classes
Please open Telegram to view this post
VIEW IN TELEGRAM
👍167🔥3
🤖 JavaBot: Telegram без магии и фреймворков

Хочешь быстро поднять Telegram-бота на Java без плясок вокруг Spring? Берём библиотеку TelegramBots, одну точку входа — и поехали.

⚙️ Подключаем зависимость

Gradle:
implementation 'org.telegram:telegrambots:6.9.7'


🧩 Создаём скелет бота
public class EchoBot extends TelegramLongPollingBot {
public String getBotUsername() { return "MyJavaBot"; }
public String getBotToken() { return "TOKEN"; }

public void onUpdateReceived(Update u) {
var chat = u.getMessage().getChatId().toString();
var text = u.getMessage().getText();
send(chat, "Ты написал: " + text);
}

void send(String chatId, String msg) {
try { execute(new SendMessage(chatId, msg)); }
catch (Exception e) { e.printStackTrace(); }
}
}


🚀 Запускаем бота
var bots = new TelegramBotsApi(DefaultBotSession.class);
bots.registerBot(new EchoBot());
System.out.println("Бот в деле 🚀");


💬 Тест
Ты: ping  
Бот: Ты написал: ping


🧠 Добавим немного логики
if (text.equals("/start"))
send(chat, "Привет! Я Java-бот 💪");
else if (text.equalsIgnoreCase("время"))
send(chat, LocalTime.now().toString());
else
send(chat, "Команда не понята 🤖");


⚡️ Inline-кнопки
var markup = new InlineKeyboardMarkup();
markup.setKeyboard(List.of(List.of(
new InlineKeyboardButton("Сказать hi").callbackData("hi")
)));
msg.setReplyMarkup(markup);


🧱 Структура проекта
src/
├── Main.java
└── EchoBot.java
build.gradle


🗣 Запомни: в Java всё строго — но именно поэтому Telegram-боты тут живут годами, не падают и не висят в “reconnecting…”
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥42
💸 Java + Финансы: low-latency трейдинг под миллисекунды

Когда миллисекунды — это деньги, Java раскрывает себя на максимум: низкоуровневые сокеты, реактивные потоки, pinned GC и прямой доступ к памяти. Тут не про «финтех-приложение», а про «реакцию быстрее всех».

🚀 1. TCP-сокеты для прямого подключения к бирже
Socket socket = new Socket("api.exchange.com", 4001);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

out.println("SUBSCRIBE:BTC-USD");
System.out.println("Tick: " + in.readLine());

➡️ Без HTTP, без JSON — только байты и скорость.

⚡️ 2. NIO (Reactor-стиль) — обрабатываем десятки потоков данных без блокировок
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open(new InetSocketAddress("api.exchange.com", 8080));
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);

while (true) {
selector.select();
for (SelectionKey key : selector.selectedKeys())
((SocketChannel) key.channel()).read(ByteBuffer.allocate(1024));
}

Ты читаешь данные в event-loop без ожиданий и блокировок.

💹 3. Лёгкий REST-клиент для котировок — минимальный overhead
HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT")).build();
String body = client.send(req, HttpResponse.BodyHandlers.ofString()).body();
System.out.println(body);

➡️ Используется редко — только для инициализации данных.

🧩 4. Реактивные потоки — стриминг обновлений без лагов
Flux.interval(Duration.ofMillis(10))
.flatMap(i -> fetchTick())
.subscribe(System.out::println);

Поддерживаешь live-данные с минимальной задержкой.

⚙️ 5. Kafka для внутренней шины котировок
ProducerRecord<String, String> tick = new ProducerRecord<>("ticks", "BTC", json);
producer.send(tick);

➡️ Kafka — идеальный посредник между стратегией и обработчиком сигналов.

📈 6. Резервный кеш в LMAX Disruptor
Disruptor<Event> disruptor = new Disruptor<>(Event::new, 1024, Executors.defaultThreadFactory());
disruptor.handleEventsWith((event, seq, end) -> process(event));
disruptor.start();

Микросекундные задержки между событиями — идеально для high-freq.

🧠 7. Обработка стратегий — минимальный GC и аллокации
double pnl = 0.0;
for (int i = 0; i < prices.length; i++)
pnl += (prices[i] - avg) * weights[i];

➡️ Никаких boxed-типов, никаких потоков — чистая арифметика.

🕹 8. Async запись в базу через Chronicle Queue
ChronicleQueue queue = ChronicleQueue.single("trades");
ExcerptAppender appender = queue.acquireAppender();
appender.writeText("BUY BTC 1.234 @ 67900");

Без JDBC, без GC, с записью прямо в память.

📡 9. Ping-тест задержки на уровне API
long t1 = System.nanoTime();
client.send(request, HttpResponse.BodyHandlers.discarding());
System.out.println("Latency: " + (System.nanoTime() - t1) / 1_000_000.0 + " ms");

➡️ Измеряй свои реальные RTT-времена, а не верь документации.

🔒 10. Failover на другом потоке без паузы
CompletableFuture.supplyAsync(() -> fetch("exchangeA"))
.exceptionally(e -> fetch("exchangeB"))
.thenAccept(this::trade);

Если один источник умер — переходишь мгновенно на другой.

📊 11. Garbage-free JSON парсер для потоков данных
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(stream);
while (parser.nextToken() != JsonToken.END_OBJECT)
process(parser.getCurrentName(), parser.getValueAsString());

➡️ Никаких String, никаких List — только поток и числа.

⏱️ 12. Синхронизация времени с NTP
NtpV3Packet msg = new NtpV3Impl();
msg.setMode(3);
System.out.println("Offset: " + client.getTime(InetAddress.getByName("pool.ntp.org")).getOffset());

В high-freq даже миллисекундный дрейф — это баг.

🗣️ Запомни: в мире Java-трейдинга твой главный конкурент — не другой разработчик, а время Garbage Collector’а.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92
🔬 Java под микроскопом: полный observability-стек с OpenTelemetry

Когда прод «горит», а метрики молчат — ты не DevOps, ты шаман.
OpenTelemetry превращает хаос в прозрачность: метрики, трейсы, логи — всё в единой системе.
Ни теории, ни лекций — только практика, как сделать observability-стек, который реально работает.

🔥 1. Подключаем OpenTelemetry SDK
implementation("io.opentelemetry:opentelemetry-api:1.31.0")
implementation("io.opentelemetry:opentelemetry-sdk:1.31.0")
implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.31.0")

➡️ Эти три зависимости — ядро: API, SDK и экспорт в OTLP (универсальный протокол).

⚙️ 2. Инициализация провайдера трейсинга
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build())
.build();

OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.build();

Настраиваешь, кто будет собирать и куда шлёт трейсы.

🧩 3. Создаём спаны прямо в коде
Tracer tracer = openTelemetry.getTracer("com.trading.app");
try (Scope scope = tracer.spanBuilder("DB Query").startScopedSpan()) {
db.execute("SELECT * FROM orders");
}

➡️ Каждый участок кода можно измерить и потом визуализировать в Grafana Tempo или Jaeger.

📊 4. Метрики: CPU, latency, GC — всё под контролем
Meter meter = openTelemetry.getMeter("com.trading.metrics");
LongCounter reqCount = meter.counterBuilder("http.requests.total").build();

reqCount.add(1, Attributes.of(stringKey("endpoint"), "/api/trade"));

Теперь ты знаешь, сколько, откуда и как часто — без лишнего логирования.

📈 5. Интеграция с Prometheus
OtlpGrpcMetricExporter exporter = OtlpGrpcMetricExporter.builder()
.setEndpoint("http://localhost:4317")
.build();

➡️ Метрики попадают в Prometheus, а дальше — Grafana dashboards.

🪵 6. Логирование в едином формате
logger.info("order_created", kv("user", userId), kv("amount", amount));

Через OpenTelemetry Logs SDK ты получаешь корреляцию между логами и трейсами.

🌐 7. Автоинструментирование без кода
java -javaagent:opentelemetry-javaagent.jar \
-Dotel.service.name=order-service \
-Dotel.exporter.otlp.endpoint=http://localhost:4317 \
-jar app.jar

➡️ Автоматически собираются спаны из Spring, JDBC, Kafka, Redis и HTTP-клиентов.

🧠 8. Отправка данных в локальный Collector
receivers:
otlp:
protocols:
grpc:
http:

exporters:
prometheus:
logging:
jaeger:
endpoint: "localhost:14250"

service:
pipelines:
traces: { receivers: [otlp], exporters: [jaeger, logging] }
metrics: { receivers: [otlp], exporters: [prometheus] }

OpenTelemetry Collector — сердце стека: маршрутизирует всё.

🚀 9. Связка Jaeger + Prometheus + Loki
Traces → Jaeger  
Metrics → Prometheus
Logs → Loki

➡️ Полная наблюдаемость: один ID связывает всё — от HTTP-запроса до GC-паузы.

🧩 10. Добавляем контекст трассировки в логи
MDC.put("traceId", Span.current().getSpanContext().getTraceId());
logger.info("processing order {}", orderId);

Теперь по traceId можно прыгнуть из Loki прямо в Jaeger.

🕹 11. Настройка дашбордов в Grafana
➡️ CPU / Memory / GC Time
➡️ Request latency per endpoint
➡️ Top error spans per service
➡️ Logs correlated by traceId

Всё видно, всё связано, всё в одном UI.

🧠 12. Distributed tracing на проде
try (Scope scope = tracer.spanBuilder("match_order").startScopedSpan()) {
orderService.match(order);
}

➡️ С каждой операцией передаётся trace-контекст по HTTP-заголовкам — видишь цепочку от frontend до БД.

🗣️ Запомни: Observability — это не «чтобы было красиво», а чтобы не гадать в тьме, где у тебя течёт прод.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥53👍3
⌨️ Для чего используется оператор assert?

Assert (Утверждение) — это специальная конструкция, позволяющая проверять предположения о значениях произвольных данных в произвольном месте программы. Утверждение может автоматически сигнализировать об обнаружении некорректных данных, что обычно приводит к аварийному завершению программы с указанием места обнаружения некорректных данных.

Утверждения существенно упрощают локализацию ошибок в коде. Даже проверка результатов выполнения очевидного кода может оказаться полезной при последующем рефакторинге, после которого код может стать не настолько очевидным и в него может закрасться ошибка.

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

Так как утверждения могут быть удалены на этапе компиляции либо во время исполнения программы, они не должны менять поведение программы. Если в результате удаления утверждения поведение программы может измениться, то это явный признак неправильного использования assert. Таким образом, внутри assert нельзя вызывать методы, изменяющие состояние программы, либо внешнего окружения программы.

В Java проверка утверждений реализована с помощью оператора assert, который имеет форму:

assert [Выражение типа boolean]; или assert [Выражение типа boolean] : [Выражение любого типа, кроме void];

Во время выполнения программы в том случае, если поверка утверждений включена, вычисляется значение булевского выражения, и если его результат false, то генерируется исключение java.lang.AssertionError. В случае использования второй формы оператора assert выражение после двоеточия задаёт детальное сообщение о произошедшей ошибке (вычисленное выражение будет преобразовано в строку и передано конструктору AssertionError).
Please open Telegram to view this post
VIEW IN TELEGRAM
4🔥1
Media is too big
VIEW IN TELEGRAM
☕️ Java в 2025 году: стоит ли учить и что изменилось

В этом видео автор анализирует, насколько Java остаётся актуальной в 2025 году и какие изменения произошли в языке и экосистеме.
Разбираются ключевые области применения Java — от корпоративных систем и Android-разработки до backend-сервисов — и сравнивается её востребованность с другими языками программирования.


👉 Ссылка на первоисточник

🗣️Запомни: Java не теряет позиции — она просто становится инструментом для тех, кто хочет стабильности и глубины в IT.

🤩  Java Фишки и трюки || #Видео
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍1
🌐 REST и RESTful API

REST (Representational State Transfer) — это архитектурный стиль для проектирования сетевых приложений. Он использует стандартные методы HTTP и акцентирует внимание на взаимодействии между клиентом и сервером с помощью ресурсов.

Основные принципы REST:

1️⃣ Клиент-серверная архитектура:
- Четкое разделение между клиентом и сервером. Клиент отвечает за пользовательский интерфейс, а сервер — за обработку данных и бизнес-логику.

2️⃣ Статус и состояние:
- Каждый запрос от клиента к серверу должен содержать всю необходимую информацию для обработки запроса. Сервер не хранит состояние сеанса (stateless).

3️⃣ Кэшируемость:
- Ответы должны быть явно обнародованы как кэшируемые или не кэшируемые. Это позволяет уменьшить количество запросов к серверу и улучшает производительность.

4️⃣ Единообразие интерфейса:
- Все взаимодействия между клиентом и сервером осуществляются через четкий и единообразный интерфейс, что упрощает интеграцию.

5️⃣ Многоуровневость:
- Система может быть структурирована на несколько уровней, где каждый уровень может вызывать другой, обеспечивая гибкость и упрощая управление.


RESTful API — это API, который следует принципам REST. Это интерфейс, который использует стандартные HTTP методы для выполнения операций с ресурсами, представленными в виде URI.

Основные HTTP методы в RESTful API:

1️⃣ GET:
- Используется для получения информации о ресурсе.
- Пример: GET /users — получить список всех пользователей.

2️⃣ POST:
- Используется для создания нового ресурса.
- Пример: POST /users — создать нового пользователя.

3️⃣ PUT:
- Используется для обновления существующего ресурса (полное обновление).
- Пример: PUT /users/1 — обновить информацию о пользователе с ID=1.

4️⃣ PATCH:
- Используется для частичного обновления ресурса.
- Пример: PATCH /users/1 — обновить определенные поля у пользователя с ID=1.

5️⃣ DELETE:
- Используется для удаления ресурса.
- Пример: DELETE /users/1 — удалить пользователя с ID=1.

RESTful API обычно возвращают данные в форматах:

- JSON (JavaScript Object Notation): легковесный формат, который легко читаем и записывается как людьми, так и машинами. Это самый распространенный формат для передачи данных в RESTful API.

- XML (eXtensible Markup Language): более старый формат, который также используется, но менее популярен в новых приложениях.

Применение RESTful API:

✔️ Веб-приложения: RESTful API часто используются в веб-приложениях для взаимодействия с серверами и базами данных.

✔️ Мобильные приложения: Многие мобильные приложения используют RESTful API для получения данных.

✔️ Интеграция систем: RESTful API позволяют различным системам взаимодействовать друг с другом с минимальными усилиями.

#REST #RESTfulAPI #API
👍6🔥21
⌨️ Внутренняя реализация ArrayList

ArrayList — это реализация динамического массива из стандартной библиотеки коллекций java.util. Он представляет собой список, который может изменять свой размер в зависимости от количества добавляемых элементов.

ArrayList основан на массиве объектов. Это означает, что под капотом у него есть массив фиксированного размера. Когда этот массив заполняется, создается новый массив большего размера, в который копируются элементы старого массива, а затем старый массив удаляется.

Размер и емкость

✔️ Размер (size) — это количество элементов, которые фактически содержатся в ArrayList.

✔️ Емкость (capacity) — это текущий размер внутреннего массива. Когда количество элементов превышает емкость, массив расширяется.

Когда ArrayList инициализируется, его емкость по умолчанию равна 10. Если количество элементов в массиве превышает емкость, массив автоматически увеличивается. Обычно емкость увеличивается по формуле: новая емкость = старая емкость * 1.5.

Для удаления элементов используется метод remove(int index). После удаления элемента все элементы, находящиеся справа от удаленного, смещаются на одну позицию влево, что требует временных затрат O(n).

После удаления элементов ArrayList не автоматически уменьшает емкость внутреннего массива, то есть массив может занимать больше памяти, чем требуется для хранения фактических элементов. Однако для оптимизации можно вручную уменьшить емкость до текущего размера с помощью метода trimToSize().

Одним из преимуществ ArrayList является возможность доступа к элементам по индексу за время O(1). Это возможно благодаря тому, что элементы хранятся в массиве, и доступ к ним осуществляется через индекс.

#java #ArrayList
Please open Telegram to view this post
VIEW IN TELEGRAM
👍153🥰1