Разбираем Collectors: 7 полезных приёмов для агрегации данных в Java!
Когда нужно не просто пройтись по списку, а сгруппировать элементы, собрать Map, посчитать статистику или подготовить вложенную структуру, обычного map/filter часто уже мало. Эти Collectors помогают писать компактнее и не превращать обработку коллекций в ручные циклы с временными Map и List.
👉 Java Ready | #шпора
Когда нужно не просто пройтись по списку, а сгруппировать элементы, собрать Map, посчитать статистику или подготовить вложенную структуру, обычного map/filter часто уже мало. Эти Collectors помогают писать компактнее и не превращать обработку коллекций в ручные циклы с временными Map и List.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍4❤2
Напоминалка по concurrent-коллекциям в Java!
Например, ConcurrentHashMap помогает безопасно работать с Map из нескольких потоков, а BlockingQueue удобна для схем producer/consumer.
На картинке шпаргалка по java.util.concurrent: concurrent lists/sets, ConcurrentMap, очереди, BlockingQueue, Deque и основным операциям добавления, удаления и просмотра элементов.
Сохрани, чтобы не потерять!
👉 Java Ready | #ресурс
Например, ConcurrentHashMap помогает безопасно работать с Map из нескольких потоков, а BlockingQueue удобна для схем producer/consumer.
На картинке шпаргалка по java.util.concurrent: concurrent lists/sets, ConcurrentMap, очереди, BlockingQueue, Deque и основным операциям добавления, удаления и просмотра элементов.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥3
Почему BigDecimal лучше не создавать из double?
BigDecimal часто используют для денег, процентов и точных вычислений:
На первый взгляд всё нормально: хотели получить 0.1.
Но double хранит число в бинарном формате, и многие десятичные дроби там не представляются точно. Поэтому BigDecimal получает не “0.1”, а фактическое значение double.
Это легко увидеть:
Результат может выглядеть примерно так:
Для точных десятичных значений лучше передавать строку:
Или использовать valueOf(), если значение уже пришло как double:
valueOf() берёт строковое представление double и обычно даёт ожидаемый десятичный результат.
Особенно важно помнить это в расчётах с деньгами:
BigDecimal точный, но только если дать ему точное входное значение. Для денег и бизнес-логики не создавай его напрямую из double.
👉 Java Ready | #совет
BigDecimal часто используют для денег, процентов и точных вычислений:
BigDecimal price = new BigDecimal(0.1);
На первый взгляд всё нормально: хотели получить 0.1.
Но double хранит число в бинарном формате, и многие десятичные дроби там не представляются точно. Поэтому BigDecimal получает не “0.1”, а фактическое значение double.
Это легко увидеть:
System.out.println(new BigDecimal(0.1));
Результат может выглядеть примерно так:
0.100000000000000005551115123125...
Для точных десятичных значений лучше передавать строку:
BigDecimal price = new BigDecimal("0.1");Или использовать valueOf(), если значение уже пришло как double:
BigDecimal price = BigDecimal.valueOf(0.1);
valueOf() берёт строковое представление double и обычно даёт ожидаемый десятичный результат.
Особенно важно помнить это в расчётах с деньгами:
BigDecimal total = new BigDecimal("19.99")
.multiply(new BigDecimal("3"));BigDecimal точный, но только если дать ему точное входное значение. Для денег и бизнес-логики не создавай его напрямую из double.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🔥3
Интересная статья про реализацию Spring-подобного API на Java с нуля!
В этой статье:
• Как устроить простые аннотации для описания компонентов
• Как вручную искать классы и создавать объекты
• Как на базовом уровне реализовать идею dependency injection
👉 Java Ready | #статья
В этой статье:
• Как устроить простые аннотации для описания компонентов
• Как вручную искать классы и создавать объекты
• Как на базовом уровне реализовать идею dependency injection
Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🔥3
Почему Stream.toList() может сломать старый код?
В Java часто собирают stream в список:
Выглядит почти так же, как старый вариант через Collectors:
Но есть важное отличие.
Stream.toList() возвращает неизменяемый список:
Если список нужен только для чтения, это даже плюс:
Так код явно показывает, что результат не должен случайно меняться после сборки.
Но если дальше список нужно дополнять, лучше создать изменяемую коллекцию явно:
Или сделать копию:
👉 Java Ready | #совет
В Java часто собирают stream в список:
List<String> names = users.stream()
.map(User::name)
.toList();
Выглядит почти так же, как старый вариант через Collectors:
List<String> names = users.stream()
.map(User::name)
.collect(Collectors.toList());
Но есть важное отличие.
Stream.toList() возвращает неизменяемый список:
List<String> names = users.stream()
.map(User::name)
.toList();
names.add("admin"); // UnsupportedOperationException
Если список нужен только для чтения, это даже плюс:
return users.stream()
.filter(User::active)
.map(User::name)
.toList();
Так код явно показывает, что результат не должен случайно меняться после сборки.
Но если дальше список нужно дополнять, лучше создать изменяемую коллекцию явно:
List<String> names = users.stream()
.map(User::name)
.collect(Collectors.toCollection(ArrayList::new));
Или сделать копию:
List<String> names = new ArrayList<>(
users.stream().map(User::name).toList()
);
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍4🔥3
Шпаргалка по Spring-аннотациям в Java!
Например, @RestController объединяет контроллер и @ResponseBody, а @Autowired связывает зависимости внутри Spring-компонента.
На картинке основные Spring Boot, Web и Framework-аннотации: @SpringBootApplication, @Controller, @RequestMapping, @PathVariable, @Configuration, @ComponentScan, @Service, @Bean, @Primary, @Profile и другие.
Сохрани, чтобы не потерять!
👉 Java Ready | #ресурс
Например, @RestController объединяет контроллер и @ResponseBody, а @Autowired связывает зависимости внутри Spring-компонента.
На картинке основные Spring Boot, Web и Framework-аннотации: @SpringBootApplication, @Controller, @RequestMapping, @PathVariable, @Configuration, @ComponentScan, @Service, @Bean, @Primary, @Profile и другие.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥5👍4
Делаем простой retry для нестабильной операции в Java!
В реальных приложениях операции иногда падают временно: сеть моргнула, сервис ответил 503, база не успела принять соединение. В таких случаях полезно повторить действие несколько раз, а не сразу завершать сценарий ошибкой.
Опишем функциональный интерфейс для операции:
Теперь зададим количество попыток:
И задержку между ними:
Базовая идея такая:
Но нужно сохранить последнюю ошибку, если все попытки закончились неудачей:
Соберём retry в метод:
Теперь можно обернуть нестабильную операцию:
Если операция сработает со второй или третьей попытки, код продолжит выполнение. Если нет, наружу уйдёт последняя ошибка.
В production-коде к retry часто добавляют экспоненциальную задержку, логирование и ограничение по типам исключений.
👉 Java Ready | #практика
В реальных приложениях операции иногда падают временно: сеть моргнула, сервис ответил 503, база не успела принять соединение. В таких случаях полезно повторить действие несколько раз, а не сразу завершать сценарий ошибкой.
Опишем функциональный интерфейс для операции:
@FunctionalInterface
interface ThrowingSupplier<T> {
T get() throws Exception;
}
Теперь зададим количество попыток:
int attempts = 3;
И задержку между ними:
Duration delay = Duration.ofMillis(300);
Базовая идея такая:
try {
return action.get();
} catch (Exception e) {
Thread.sleep(delay.toMillis());
}Но нужно сохранить последнюю ошибку, если все попытки закончились неудачей:
Exception lastError = null;
Соберём retry в метод:
static <T> T retry(
ThrowingSupplier<T> action,
int attempts,
Duration delay
) throws Exception {
Exception lastError = null;
for (int i = 1; i <= attempts; i++) {
try {
return action.get();
} catch (Exception e) {
lastError = e;
if (i < attempts) {
Thread.sleep(delay.toMillis());
}
}
}
throw lastError;
}
Теперь можно обернуть нестабильную операцию:
String response = retry(
() -> loadFromRemoteApi(),
3,
Duration.ofMillis(300)
);
Если операция сработает со второй или третьей попытки, код продолжит выполнение. Если нет, наружу уйдёт последняя ошибка.
В production-коде к retry часто добавляют экспоненциальную задержку, логирование и ограничение по типам исключений.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍3🔥2
Media is too big
VIEW IN TELEGRAM
Java Code Geeks — огромная база туториалов и примеров по Java!
На сайте собраны материалы по Core Java, Java 8/9, concurrency, NIO, logging, design patterns, exceptions, JUnit, Mockito, Spring Boot, Spring MVC, Spring Security, Hibernate, JPA, JDBC, JavaFX и другим темам. Это не одностраничный справочник, а большая база статей и практических примеров: можно листать разделы, открывать конкретные технологии и быстро находить готовые разборы под реальные задачи backend-разработки.
👉 Java Ready | #ресурс
На сайте собраны материалы по Core Java, Java 8/9, concurrency, NIO, logging, design patterns, exceptions, JUnit, Mockito, Spring Boot, Spring MVC, Spring Security, Hibernate, JPA, JDBC, JavaFX и другим темам. Это не одностраничный справочник, а большая база статей и практических примеров: можно листать разделы, открывать конкретные технологии и быстро находить готовые разборы под реальные задачи backend-разработки.
Оставляю ссылочку: Java Code Geeks
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍4🔥4
Как сортировать в Java, если в данных бывают null?
Обычная сортировка по полю выглядит просто:
Но если
Например:
Для таких случаев в Comparator есть специальные обёртки:
Теперь null можно отправить в конец:
Результат будет предсказуемым:
Если null нужно поставить в начало, есть nullsFirst:
То же самое удобно для дат, email, optional-полей из базы и данных из внешних API:
Так сортировка явно показывает бизнес-правило: пустые значения не ломают код, а уходят туда, куда нужно.
Если поле для сортировки может быть null, лучше сразу описать это через nullsFirst/nullsLast, а не надеяться, что данные всегда идеальные.
👉 Java Ready | #совет
Обычная сортировка по полю выглядит просто:
users.sort(Comparator.comparing(User::name));
Но если
name() у какого-то пользователя вернёт null, сортировка может упасть с NullPointerException.Например:
record User(String name) {}
var users = new ArrayList<>(List.of(
new User("Bob"),
new User(null),
new User("Ann")
));Для таких случаев в Comparator есть специальные обёртки:
Comparator.nullsLast(String::compareTo)
Теперь null можно отправить в конец:
users.sort(Comparator.comparing(
User::name,
Comparator.nullsLast(String::compareTo)
));
Результат будет предсказуемым:
Ann
Bob
null
Если null нужно поставить в начало, есть nullsFirst:
users.sort(Comparator.comparing(
User::name,
Comparator.nullsFirst(String::compareTo)
));
То же самое удобно для дат, email, optional-полей из базы и данных из внешних API:
orders.sort(Comparator.comparing(
Order::paidAt,
Comparator.nullsLast(Comparator.naturalOrder())
));
Так сортировка явно показывает бизнес-правило: пустые значения не ломают код, а уходят туда, куда нужно.
Если поле для сортировки может быть null, лучше сразу описать это через nullsFirst/nullsLast, а не надеяться, что данные всегда идеальные.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2🔥2
Делаем дедупликацию событий на Java!
Если webhook, очередь или внешний сервис повторно присылает одно и то же событие, бизнес-логика не должна выполняться дважды. Соберём простой обработчик, который запоминает eventId и пропускает дубли.
В этой задаче:
Такой подход помогает избежать повторных списаний, дублей уведомлений и лишней обработки при retry-механиках.
👉 Java Ready | #задача
Если webhook, очередь или внешний сервис повторно присылает одно и то же событие, бизнес-логика не должна выполняться дважды. Соберём простой обработчик, который запоминает eventId и пропускает дубли.
В этой задаче:
• Храним обработанные id в Set;
• Используем add() как проверку на повтор;
• Выполняем действие только для новых событий.
Такой подход помогает избежать повторных списаний, дублей уведомлений и лишней обработки при retry-механиках.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🔥2
Отличная статья про создание собственного Spring Boot 3 starter’а на Java!
В этой статье:
• Как starter превращается в отдельный переиспользуемый блок конфигурации
• Как добавить автоконфигурацию, default-настройки и EnvironmentPostProcessor
• Как собрать стартер и подключить его к обычному Spring Boot-приложению
👉 Java Ready | #статья
В этой статье:
• Как starter превращается в отдельный переиспользуемый блок конфигурации
• Как добавить автоконфигурацию, default-настройки и EnvironmentPostProcessor
• Как собрать стартер и подключить его к обычному Spring Boot-приложению
Продолжай читать на Habr!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
Dev.java — ресурс по современной Java!
На сайте собраны материалы от Java-команды: Getting Started, основы языка, Collections Framework, Stream API, Virtual Threads, JShell, инструменты сборки, IDE, новые возможности платформы и отдельные разделы для более глубокого изучения. Хорошо подходит не только новичкам, но и тем, кто хочет освежить современную Java без случайных устаревших примеров.
Оставляю ссылочку: dev.java
👉 Java Ready | #ресурс
На сайте собраны материалы от Java-команды: Getting Started, основы языка, Collections Framework, Stream API, Virtual Threads, JShell, инструменты сборки, IDE, новые возможности платформы и отдельные разделы для более глубокого изучения. Хорошо подходит не только новичкам, но и тем, кто хочет освежить современную Java без случайных устаревших примеров.
Оставляю ссылочку: dev.java
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤5🔥5
Делаем простой rate limiter на Java!
Иногда нужно ограничить частоту действий: отправку кода подтверждения, вызов команды, обращение к endpoint или повторную отправку формы. Для базового варианта можно использовать очередь с временем последних успешных вызовов.
В этой задаче:
Такой вариант хорошо подходит для понимания идеи sliding window и небольших локальных сценариев.
👉 Java Ready | #задача
Иногда нужно ограничить частоту действий: отправку кода подтверждения, вызов команды, обращение к endpoint или повторную отправку формы. Для базового варианта можно использовать очередь с временем последних успешных вызовов.
В этой задаче:
• храним timestamps действий;
• удаляем устаревшие записи;
• проверяем размер окна;
Такой вариант хорошо подходит для понимания идеи sliding window и небольших локальных сценариев.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3🔥1