Java Portal | Программирование
13.2K subscribers
1.16K photos
95 videos
37 files
1.07K links
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика

Связь: @devmangx

РКН: https://clck.ru/3H4WUg
Download Telegram
Совет по Spring Boot

RestTestClient для тестирования API

RestTestClient это единый инструмент для тестирования REST API, который можно использовать вместо WebTestClient, TestRestTemplate (удалён) или MockMVC.

1. Определи объект RestTestClient в тесте
2. Привяжи его к конкретному компоненту. Это может быть controller, MockMVC, server или Spring context
3. Потом используй RestTestClient в тесте

@SpringBootTest
public class PersonControllerWithHeadersTests {

private WebApplicationContext context;
private RestTestClient restTestClient;

@BeforeEach
public void setup(WebApplicationContext context) {
restTestClient = RestTestClient
.bindToApplicationContext(context)
.build();
}

@Test
void addPersonTest() {
restTestClient.post()
.uri("/persons")
.body(Instancio.create(Person.class))
.exchange()
.expectStatus().is2xxSuccessful()
.expectBody(Person.class)
.value(p -> assertNotNull(p.getId()));
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3
Java-подсказка: начиная с Java 11, если нужно повторить строку n раз, можно использовать метод repeat(n) у String.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍3🔥3😁1
Если у тебя начинают получаться сложные вложенные подзапросы, лучше перейти на CTE , чтобы сделать запросы читабельнее.

CTE позволяет вынести часть логики в отдельный блок и использовать результат как временную таблицу. Это помогает структурировать запросы и делать их понятнее.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17
Java-команды часто ищут прорывы не там.

Spring + JVM получает больше профита от Kotlin, чем от попыток перезабрести фреймворк.

Kotlin прокачивает базу.

А именно база решает, движется ли команда быстро или нет

1. Код становится проще.

Меньше шаблонного мусора.
Более безопасные дефолты.
Четче выраженные намерения.
Команда делает те же фичи быстрее и с меньшим количеством багов.

2. Работа с конкурентностью становится чище.

Коррутины стабильнее и удобнее, чем вечная возня с потоками.
Та же JVM. Тот же Spring.
Но асинхронный код наконец становится предсказуемым

3. Миграция с низкими рисками.

Никаких переписанных с нуля сервисов.
Никаких параллельных стеков.
Никакого большого взрыва.
Kotlin можно внедрять точечно - новые модули, новые сервисы, тесты, внутренние тулзы.
Эффект накапливается довольно быстро.

Так выглядит распространенный сценарий в успешных командах:

Один инженер пробует -> остальные замечают разницу -> adoption летит вверх.

4. Бизнес тоже ощущает разницу.

Меньше дефектов.
Быстрее онбординг.
Выше скорость разработки.
Лучше асинхронное поведение.
И все это без замены стека.

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

Если ты уже на Spring + JVM, это самый выгодный апгрейд, который можно выкатить хоть завтра 🍌

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🤣6🔥3🤔2💊2🌭1
Какой Java Map быстрее для 1 млн обращений?

Производительность (в среднем):

HashMap get(): ~0.8 ms (O(1))

TreeMap get(): ~15 ms (O(log n))

HashMap put(): ~1.2 ms

TreeMap put(): ~18 ms


HashMap выигрывает по сырым скоростям примерно в 15–20 раз.

TreeMap жертвует производительностью ради отсортированного порядка ключей.

HashMap использует хеширование с операциями за амортизированное константное время.

TreeMap использует красно-черное дерево, гарантируя O(log n), но за счет скорости.

Используй HashMap, когда важна скорость, и TreeMap, когда нужны отсортированные ключи или диапазонные запросы.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
10👍6🔥3
Быстрый Kafka consumer на виртуальных потоках.

Каждое новое сообщение, которое получает listener, обрабатывается в отдельном виртуальном потоке.

Естественно, при таком подходе теряется порядок сообщений внутри одного partition.

Выбирай, что для тебя важнее.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍2
Подсказка по Java: начиная с Java 11 можно использовать String.strip() вместо trim(), потому что strip() корректно обрабатывает пробелы в Unicode.

Так как trim() не обрабатывает некоторые типы пробелов, определенные в Unicode, он может оставлять неожиданные символы.

String.strip() использует Character.isWhitespace(int codePoint) для определения пробельных символов, учитывая полный стандарт Unicode, а не только ASCII, и удаляет все виды пробелов.

Пример:

String text = "\u2003Hello World\u2003";
System.out.println("trim(): [" + text.trim() + "]");
System.out.println("strip(): [" + text.strip() + "]");


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍254
This media is not supported in your browser
VIEW IN TELEGRAM
Это расширение для Chrome прям находка для тех, кто активно сидит на GitHub

Называется SimRepo и показывает похожие репозитории для любого открытого проекта.

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

Полезно, если хочешь найти что-то лучше, посмотреть альтернативы или просто открыть для себя новые проекты во время поиска ☺️

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
13🔥3👍2👀1
Совет по Java: используй WeakHashMap для кеширования, если ключи без ссылок должны автоматически очищаться сборщиком мусора.

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

В WeakHashMap ключи хранятся через слабые ссылки, и если на ключ больше нет сильных ссылок в других частях программы, GC может освободить его, и он будет автоматически удалён из карты.

Пример:

Map<User, String> map = new WeakHashMap<>();

User u1 = new User("Mick");
map.put(u1, "Cached data");
...
u1 = null;

// Теперь ключ u1 может быть собран сборщиком мусора.


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍93🔥2
Уменьшаем время выборки из БД с 2–3 секунд до ~100 мс:

SELECT * FROM transactions
WHERE user_id = 40
ORDER BY created_at DESC
LIMIT 20 OFFSET 10000;


На первый взгляд запрос нормальный?
ДА, вроде ок.

Но:

- это OFFSET-пагинация
- и это прям ПЛОХО
- БД вытягивает 10020 строк и выкидывает 10000, чтобы показать 20, лол
- чем больше OFFSET, тем больше нагрузка на БД
- со временем запрос начинает занимать больше 2 секунд, пока растет объем данных

Решение:

KEYSET (seek) пагинация: добавляем условие вида created_at < last_seen_timestamp

SELECT * FROM transactions
WHERE user_id = 40
AND created_at < '2024-05-01 10:00:00'
ORDER BY created_at DESC
LIMIT 20;


- так БД может сразу прыгнуть по индексу
- по сути это "дай следующие 20 записей после этого timestamp", где timestamp используется как ключ
- время реально падает с секунд до примерно 100–200 мс

Что если timestamp не уникален, есть дубли:

Добавляем tie-breaker: (created_at, id) и в WHERE, и в ORDER BY:

WHERE (created_at, id) < ('2024-05-01 10:00:00', 98765)
ORDER BY created_at DESC, id DESC


Так пагинация остается быстрой и детерминированной, даже при одинаковых created_at.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥54
Одна ключевая идея в Spring Boot, которая в 2025 отличает синьоров от staff/principal инженеров:

Большинство разработчиков думают, что Spring Boot это просто
@RestController + JPA.

Инженеры уровня staff и выше понимают, что настоящий переломный момент это относиться к потокам как к детали реализации, а не к ресурсу.

Virtual Threads (Project Loom) + Spring Boot 3 позволяют блокирующему коду масштабироваться лучше, чем это когда-либо делал реактивный стек.

Теперь не нужно выбирать упрощение или производительность. Можно иметь оба варианта сразу.

Один такой сдвиг в мышлении может поднять пропускную способность системы в 10 раз и вдвое снизить сложность.

@RestController
@RequestMapping("/api/orders")
class OrderController {

@Autowired JdbcTemplate jdbc; // Оставляй свой старый добрый блокирующий JDBC
@Autowired RestTemplate rest; // Оставляй привычный блокирующий RestTemplate
@Autowired EntityManager em; // Оставляй JPA/Hibernate в том виде, как привык

@GetMapping("/{id}")
public Order get(@PathVariable Long id) {
// 100% блокирующий код — читает БД, вызывает 3 downstream HTTP-сервиса
// Но благодаря виртуальным потокам один этот endpoint
// спокойно выдерживает 50k+ RPS на 2 vCPU при < 50 ms p99

var order = jdbc.queryForObject("SELECT * FROM orders WHERE id=?", Order.class, id);
var payment = rest.getForObject("http://payment/{id}", Payment.class, id);
var shipping = rest.getForObject("http://shipping/{id}", Shipping.class, id);

return order.withPayment(payment).withShipping(shipping);
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍3🤣3
Приглашаем на ЮMoneyDay — бесплатную онлайн-конференцию про финтех и IT 🔥

На протяжении двух дней будем общаться с разработчиками, инженерами, тестировщиками, продактами, дизайнерами и другими специалистами из ЮMoney. Они расскажут про свой опыт работы в большом финансовом продукте, поделятся лайфхаками и секретами.

Будут доклады по 16 направлениям:

🟣 Будущее финтеха
🟣 Бэкенд
🟣 Фронтенд
🟣 Тестирование
🟣 Python
🟣 Менеджмент проектов
🟣 Менеджмент продуктов
🟣 Системный анализ
🟣 SQL
🟣 UX
🟣 ИИ
🟣 Архитектура IT-решений
🟣 Внутренние системы
🟣 Мобильная разработка
🟣 Инфраструктура
🟣 О компании

Встречаемся онлайн 5 и 6 декабря в 11:00 мск. Чтобы участвовать, зарегистрируйтесь на сайте конференции
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1🔥1
Spring Modulith добавили поддержку Application-Module Aware миграций в Flyway.

Посмотреть, как это работает, можно тут👇
https://github.com/sivaprasadreddy/spring-modular-monolith

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
4🤔1
Совет по Spring Boot

Когда пишешь REST API на Spring Boot, обычно используют префикс /api

Чтобы не лепить @RequestMapping("/api") в каждом контроллере, можно настроить это один раз вот так:

@Configuration
class WebMvcConfig implements WebMvcConfigurer {

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/api",
aClass -> aClass.getPackage().getName().startsWith("com.sivalabs.bookstore"));
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍134😁1
Какой будет вывод и почему?

class Person {
String name;
}

public class Test {
static void modify(Person obj) {
obj.name = "Rahul";
obj = new Person();
obj.name = "Amit";
}

public static void main(String[] args) {
Person p = new Person();
p.name = "Sumit";

modify(p);

System.out.println(p.name);
}
}


Если ты не можешь ответить на это, значит ты пока не готов к интервью.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍5
Можно использовать асинхронный логгинг в Spring Boot, настроив logback (logback-spring.xml).

Лог-сообщения отправляются в очередь и обрабатываются отдельным фоновым потоком.

Это уменьшает задержки, связанные с вводом-выводом.

Положи файл конфигурации logback в папку resources:

src/main/resources/logback-spring.xml


Вот пример:

<configuration>

<!-- Console appender, обёрнутый в асинхронный -->
<appender name="ASYNC_CONSOLE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="CONSOLE" />
<queueSize>5000</queueSize>
<discardingThreshold>0</discardingThreshold>
<includeCallerData>false</includeCallerData>
</appender>

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger - %msg%n</pattern>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="ASYNC_CONSOLE" />
</root>

</configuration>


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52
Media is too big
VIEW IN TELEGRAM
Разработчик выложил проект ShadowStream, систему отслеживания изменений в базе данных (CDC), построенную на PostgreSQL logical replication.

Цель проекта — ловить любые изменения в реальном времени и передавать их в потоковую инфраструктуру.

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

- изменения в базе (INSERT, UPDATE, DELETE) сразу перехватываются через logical replication
- события сериализуются в Protobuf и отправляются в Redis Streams для быстрого доступа
- параллельно те же данные архивируются в Kafka для надежного хранения
- Kafka использует grouped consumer'ов: два обработчика работают параллельно, плюс резервная группа с отдельным offset
- поверх всего в Django Admin добавлена визуализация gRPC-вызовов

Исходники открыты на GitHub

Проект может пригодиться тем, кто работает с потоковой обработкой данных, аналитикой, репликацией или интеграцией микросервисов. 🙂

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥114
Java даёт много вариантов по части синтаксиса, но функциональные интерфейсы — одна из самых аккуратных и приятных фишек языка ☕️

Сегодня разберём 4 штуки, которые встречаются чаще всего. Если поймёшь их, писать код станет современнее, местами чище

Идея простая 👇

Функциональный интерфейс — это интерфейс с одним абстрактным методом. Благодаря этому его можно реализовать через лямбды.

В Java их много, но вот четыре, которые ты будешь видеть постоянно:

👉 Consumer — делает что-то

Consumer принимает значение и ничего не возвращает.

Отлично подходит для побочных эффектов: логирование, вывод в консоль, сохранение, отправка и так далее.

Consumer<String> consumer = str -> System.out.println(str);
consumer.accept("Hola");


Проще говоря:
"получи это и сделай с этим что-то".

👉 Supplier — дай что-то

Supplier ничего не принимает и возвращает значение.

Часто используется для получения конфигураций, генерации ID, ленивого создания объектов и прочего.

Supplier<Double> supplier = () -> Math.random();
supplier.get();


То есть:
"выдай нужную штуку, когда я попрошу".

👉 Function<T, R> — преобразуй что-то

Принимает значение типа T и возвращает значение типа R.

На практике эта штука — самая распространённая.

Function<Integer, String> function = number -> "N° " + number;
function.apply(5);


По смыслу:
"получаю T, возвращаю R".

👉Predicate — реши что-то (true/false)

Принимает значение и возвращает boolean.
Часто нужен для фильтрации списков, простых проверок, валидаций, правил.

Predicate<String> predicate = s -> s.length() > 5;
predicate.test("Java");


То есть:
"подходит или не подходит под условие".

Важно:

Эти интерфейсы существуют не ради компактного кода.

Они нужны, чтобы ты думал через операции, а не через классы.

Они идеально заходят в Streams, в коллбеки, в валидации, в композицию логики — везде, где есть простая операция, для которой не нужна отдельная сущность.

Это не замена всему на свете. Речь не про то, чтобы переписать всю систему в функциональном стиле.

Но они реально помогают во множестве сценариев.

Если научишься читать Function, Consumer, Supplier и Predicate, то спокойно разберёшь и напишешь современный Java-код без лишних страданий. И это уже хороший шаг вперёд. 😁

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍184🔥2🤣1
Кандидаты часто путаются, когда спрашивают:
в чем разница между rate limiting и throttling?


На самом деле всё очень просто.

* Rate limiting
Задаёт фиксированный максимум запросов.
Если превысил лимит — лишние запросы просто блокируются.
Пример: 100 запросов в минуту разрешено. 101-й — отклоняется.

* Throttling
Не блокирует. Он замедляет обработку запросов, когда ты начинаешь спамить.
Пример: после 100 запросов каждый следующий обрабатывается с задержкой, но всё равно проходит.

Запомнить легко:

Rate limiting — стоп сверхлимита.
Throttling — замедление сверхлимита.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84🤔1
Совет по Java: в JPA можно использовать native query не только для SELECT, но и для UPDATE, DELETE и INSERT. Учти, что в этом случае всё проходит мимо EntityManager и PersistenceContext.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
4🔥3👍2