12073
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика Связь: @devmangx РКН: https://clck.ru/3H4WUg
Вы предпочитаете аккуратно отформатированные текстовые блоки для аннотаций запросов при использовании Spring Data?
https://spring.io/tools теперь умеет генерировать именно такие при преобразовании AOT-метаданных репозитория в аннотации запросов
👉 Java Portal
Поставлено в JDK 22: JEP 454 добавил в Java стандартный API для работы с внешними функциями и памятью. Вызов нативного кода больше не обязан начинаться с шаблонного кода JNI. Небольшой пример 👇
Читать полностью…
Java-Инженеры, наблюдающие, как все остальные вайбкодят приложения
👉 Java Portal
Spring Boot: есть возможность использовать стриминг (Stream<T>) для запросов с большими наборами данных.
Результаты подтягиваются чанками, при этом в памяти одновременно находится только небольшая часть данных
В следующем примере есть приложение с CommandLineRunner, которое сохраняет большой набор пользователей в базу данных, а затем обрабатывает данные через стрим:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
CommandLineRunner run(UserRepository repo, UserService service) {
return args -> {
// Генерация тестовых данных
for (int i = 1; i <= 10000; i++) {
repo.save(new User("User_" + i));
}
// Обработка через стрим
service.processUsers();
};
}
}
processUsers работает в транзакции и использует метод репозитория streamAllUsers, который возвращает стрим:@Service
public class UserService {
private final UserRepository repository;
@PersistenceContext
private EntityManager em;
public UserService(UserRepository repository) {
this.repository = repository;
}
@Transactional(readOnly = true)
public void processUsers() {
AtomicInteger counter = new AtomicInteger();
try (Stream<User> stream = repository.streamAllUsers()) {
stream.forEach(user -> {
System.out.println(user.getName());
if (counter.incrementAndGet() % 100 == 0) {
em.clear();
}
});
}
}
}
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u")
Stream<User> streamAllUsers();
}spring.jpa.properties.hibernate.jdbc.fetch_size=100, так как некоторые драйверы могут загрузить всё сразу
🔴 Завтра тестовое собеседование с Java-разработчиком
15 апреля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Виктор Анохин, старший разработчик из WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Виктор будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Виктору
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе.
Прогрессивный практический туториал по изучению Agent Client Protocol (ACP) с использованием Java SDK: https://github.com/markpollack/acp-java-tutorial
👉 Java Portal
В SpringFramework 7.1 появится поддержка @MockitoBean и @MockitoSpyBean на параметрах конструктора теста
Это работает с конструкторами в Java, но ещё удобнее с компактными конструкторами в Kotlin. Также это работает с так называемыми «test records» в Java. 🤓
👉 Java Portal
Java API Tip
Безопасное приведение long к int
Используй Math.toIntExact() — этот метод возвращает значение long, но выбрасывает ArithmeticException, если оно не помещается в int
Без него преобразование произойдёт молча — и ты можешь получить некорректный результат без всяких ошибок.
Используй toIntExact, когда важно контролировать переполнение
👉 Java Portal
#Java Совет: вы можете откатить транзакцию БД, созданную аннотацией @Transactional, получив текущий TransactionStatus через класс TransactionAspectSupport и установив для него rollback через setRollbackOnly();. Таким образом, не нужно выбрасывать исключение.
👉 Java Portal
Один JEP, к которому стоит вернуться: JEP 485 в JDK 24. Он вводит gather(...) для стримов — новую промежуточную операцию для преобразований, которые не укладываются в map, filter или flatMap. Небольшой пример 👇
Большинство проектов на Spring Boot обрабатывают конфигурацию одинаково: плоские классы с @ConfigurationProperties, строковые имена свойств и надежда на то, что все прочитают README.
В Apereo CAS — более 1000 свойств в 633 конфигурационных классах. Автор написал статью о том, как система конфигурации остаётся навигируемой при таком масштабе:
https://medium.com/all-things-software/spring-boot-configuration-properties-at-scale-884f494721ac
👉 Java Portal
Java Spring Boot: Не допускайте эту ошибку с фильтрами/интерцепторами
Многие используют фильтры и интерцепторы неправильно
Они должны использоваться только для сквозных задач
(то есть для того, что применяется ко ВСЕМ запросам)
Примеры корректного использования:
[Фильтры]:
- CORS
- Кодировка
[Интерцепторы]:
- Аутентификация/Авторизация
- Метрики/Логирование
- Локаль
- Общие заголовки
[Основная ошибка]:
размещать там бизнес-логику
Например:
- выполнение запросов к базе данных
- проверка подписок
- сложная логика
Почему это плохо:
- выполняется для КАЖДОГО запроса
- создаёт дополнительную нагрузку
- нарушает архитектуру
- усложняет тестирование
Вывод:
- интерцептор превращается в «мусорный слой»
Как делать правильно:
- бизнес-логика → в сервисах
- контроллеры → оркестрация
👉 Java Portal
Spring Boot — большой фреймворк, на освоение которого могут уйти годы. Но, на мой взгляд, достаточно знать ключевые возможности и иметь практический опыт с наиболее часто используемыми фичами, чтобы считаться “готовым к работе”.
Roadmap для начинающих по Spring Boot : читать
👉 Java Portal
Продвинутый совет по Spring
Превратите структуру вашего Spring-проекта в тестируемый контракт, который никогда не будет незаметно деградировать.
С помощью Taikai вы можете принудительно проверять архитектурные ограничения с использованием предопределённых правил ArchUnit, см. документацию.
https://github.com/enofex/taikai
👉 Java Portal
Полезняшка: парень сделал небольшой плагин для IntelliJ IDEA для вещи, которая раздражала многих годами:
https://github.com/saket/intellij-comment-continuation
Плагин для IntelliJ IDEA, который продолжает // комментарии на следующей строке при нажатии Enter с сохранением отступа. Повторное нажатие Enter на пустой строке комментария завершает блок комментариев и сохраняет тот же уровень отступа.
👉 Java Portal
JavaDoc получил реальное улучшение удобства использования в Java 24.
Парень написал практический туториал, который показывает, как использовать JavaDoc с Markdown через комментарии /// в небольшой библиотеке на Maven + JUnit, включая документацию пакетов, записи, запечатанные типы, генерацию JavaDoc и всплывающие подсказки в IDE.
http://buff.ly/RmaVWSt
#Java #Java24 #Javadoc #Maven
👉 Java Portal
Совет по Java Spring Boot
Если в JSON-запросе приходят лишние поля, приложение может упасть с ошибкойUnrecognizedPropertyException.
Чтобы этого избежать и не ломать API, добавь аннотацию:
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserDTO {
private String name;
private int age;
}
Java: используйте WeakHashMap для кэширования, когда ключи без ссылок должны удаляться сборщиком мусора.
❌В HashMap, пока существует сама мапа, ключи и связанные с ними значения не будут удаляться сборщиком мусора.
✅В WeakHashMap ключи хранятся через слабые ссылки, и если на ключ больше нет сильных ссылок в программе, сборщик мусора может его удалить, и он автоматически исчезнет из мапы.
✅Пример:
Map<User, String> map = new WeakHashMap<>();
User u1 = new User("Mick");
map.put(u1, "Cached data");
...
u1 = null;
// С этого момента ключ u1 доступен для сборки мусора.
Освой Java с нуля
Этот бесплатный курс охватывает широкий спектр тем, начиная от базовых концепций, таких как переменные, массивы, условные операторы и циклы, до более сложных аспектов, включая ООП, работу с файлами, двумерные массивы и работу с базами данных.
Материалы включают теоретические объяснения, практические примеры кода, и иногда задачи для самостоятельного выполнения
⛓Ссылка: тык
👉 Java Portal
По умолчанию Spring Boot не включает stacktrace в ответах REST-сервисов. Только для целей быстрого дебага (не используйте это в production) можно включить это через конфигурационное свойство include-stacktrace: always.
#SpringBoot #JavaDev
👉 Java Portal
Spring Boot: Лучше использовать SpringBootTest.WebEnvironment.RANDOM_PORT вместо жёстко заданных портов в тестах, чтобы избежать конфликтов.
#SpringBoot #JavaDev
👉 Java Portal
💡Spring Boot: для чистых REST-контроллеров используйте@RestController вместо @Controller + @ResponseBody@RestController — это мета-аннотация, которая включает @ResponseBody, и затем автоматически применяется ко всем методам:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
}
@Controller и @ResponseBody:@Controller
public class MyController {
@ResponseBody
@GetMapping("/hello")
public String hello() {
return "Hello!";
}
}
@RestController:@RestController
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello!";
}
}
Spring Boot: лучше избегать логирования внутри плотных циклов, так как это может повлиять на производительность приложения и привести к засорению лог-файлов.
Пример:
for (Order order : orders) {
log.info("Order {}", order.getId());
process(order);
}orders большой, это может замедлить обработку и засорить лог-файлы.debug:log.debug("Order: {}", order.getId());if (log.isDebugEnabled()) {
log.debug("Order: {}", expensiveElaboration());
}
Spring Boot: можно валидировать конфигурационные классы с помощью аннотации @Validated.
✅ Это позволяет приложению падать на старте (fail fast), если конфигурация некорректна.
@Validated
@ConfigurationProperties(prefix = "app")
public class AppProperties {
@NotBlank
private String name;
@Min(1)
@Max(60)
private int timeout;
// getters/setters
}
Java 21 открывает новую эпоху конкурентности с виртуальными потоками — лёгкими потоками, управляемыми JVM, которые значительно повышают производительность I/O-bound приложений.
Подробнее - https://lttr.ai/Ap1Np
#Java #MongoDB #VirtualThread
👉 Java Portal
Совет по Java : Если нужно посчитать количество вхождений элемента в списке, можно использовать Collections.frequency(...).
#Java #Collections
👉 Java Portal
Совет по Java: начиная с Java 15 можно использовать String.formatted(...) для форматирования строк вместо String.format(...).
Работает как String.format, но выглядит немного чище и понятнее:
Вместо:
String message = String.format("Hello %s, you have %d messages", user, count);
System.out.println(String.format("Hello %s, you have %d messages", user, count));String message = "Hello %s, you have %d messages".formatted(user, count);
System.out.println("Hello %s, you have %d messages".formatted(user, count));
String json = """
{
"user": "%s",
"messages": %d
}
""".formatted(user, count);
Совет по Java: избегайте накладных расходов на boxing, используя потоки примитивов.
❌Создание объектов Integer для каждого значения:
Stream<Integer> boxed = Stream.of(1, 2, 3, 4, 5);
int sumBoxed = boxed.reduce(0, Integer::sum);
int sumPrimitive = IntStream.of(1, 2, 3, 4, 5).sum();
LongStream, DoubleStream
Один из самых ценных паттернов в Java на продакшене: неизменяемые DTO с использованием Records + Builder.
В реальных Java-приложениях (Spring Boot API, микросервисы, event-системы) мы создаем сотни DTO.
Лучший современный паттерн в 2026 году:
Records (неизменяемые по умолчанию) + паттерн Builder для гибкой инициализации.
Преимущества:
- Неизменяемость → потокобезопасность и предсказуемость
- Нет boilerplate-кода с геттерами/сеттерами
- Builder дает удобный fluent API для опциональных полей
- Отличная интеграция с Jackson, валидацией и MapStruct
Реалистичный пример из продакшена ниже:
👉 Java Portal
Spring Boot: используйте TaskScheduler для реализации лёгких динамических задач. Для более сложных сценариев стоит рассмотреть Quartz.
✅ Инжектим и используем:
...
@Autowired
TaskScheduler scheduler;
scheduler.schedule(
() -> System.out.println("Hello!"),
new CronTrigger("0 */5 * * * *") // каждые 5 минут
);
...
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5);
scheduler.setThreadNamePrefix("my-scheduler-");
scheduler.initialize();
return scheduler;
}
}