Java | Фишки и трюки
Kanalga Telegram’da o‘tish
Java: примеры кода, интересные фишки и полезные трюки Купить рекламу: https://telega.in/c/java_tips_and_tricks ✍️По всем вопросам: @Pascal4eg
Ko'proq ko'rsatish6 811
Obunachilar
-624 soatlar
-137 kunlar
-6930 kunlar
Postlar arxiv
6 811
💠Gson — это библиотека от Google, предназначенная для работы с JSON в Java-приложениях. Она позволяет легко преобразовывать объекты Java в JSON и обратно, избавляя разработчиков от необходимости писать шаблонный код для парсинга данных. Gson поддерживает сложные структуры данных, такие как коллекции, вложенные объекты и даже объекты без исходного кода.
🟣Почему стоит использовать Gson?
1.🧬 Простота интеграции: Для использования достаточно добавить зависимость в build.gradle:
implementation 'com.google.code.gson:gson:2.12.1'
2.🧬Мощные возможности сериализации и десериализации: Gson поддерживает преобразование объектов любой сложности.
3.🧬Интеграция с Retrofit: Gson часто используется в качестве конвертера для обработки данных из API.
4.🧬 Настраиваемость: С помощью GsonBuilder можно задать форматирование JSON, исключение полей и другие настройки.
⚡️Пример 1: Сериализация объекта.
➡️Сериализация — это процесс преобразования объекта Java в строку JSON. Рассмотрим простой пример:
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
➡️Создадим объект User и преобразуем его в JSON:
Gson gson = new Gson();
User user = new User("John", 25);
String json = gson.toJson(user);
System.out.println(json);
➡️Результат:
{"name":"John","age":25}
⚡️Пример 2: Десериализация JSON
➡️Десериализация — это обратный процесс, преобразующий строку JSON в объект Java:
String json = "{\"name\":\"Jane\",\"age\":30}";
User user = gson.fromJson(json, User.class);
System.out.println("Имя: " + user.getName() + ", Возраст: " + user.getAge());
➡️Результат:
Имя: Jane, Возраст: 30
⚡️Пример 3: Работа с коллекциями
➡️Если данные представлены в виде массива JSON, Gson может преобразовать их в список объектов:
String jsonArray = "[{\"name\":\"John\",\"age\":25},{\"name\":\"Jane\",\"age\":30}]";
Type userListType = new TypeToken<List<User>>() {}.getType();
List<User> users = gson.fromJson(jsonArray, userListType);
for (User user : users) {
System.out.println("Имя: " + user.getName() + ", Возраст: " + user.getAge());
}
➡️Результат:
Имя: John, Возраст: 25
Имя: Jane, Возраст: 30
⚡️Пример 4: Настройка через GsonBuilder.
➡️С помощью GsonBuilder можно настроить форматирование JSON или исключение определённых полей:
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.excludeFieldsWithoutExposeAnnotation()
.create();
String json = gson.toJson(user);
System.out.println(json);
➡️Результат будет отформатирован для удобного чтения:
{
"name": "John",
"age": 25
}
💎Обработка ошибок при десериализации
➡️Если формат JSON некорректен или не соответствует ожидаемому, может возникнуть ошибка JsonSyntaxException. Чтобы избежать краша приложения, используйте блок try-catch:
try {
User user = gson.fromJson("{invalid_json}", User.class);
} catch (JsonSyntaxException e) {
e.printStackTrace();
}6 811
🔍Тестовое собеседование на Middle Java-разработчика завтра
9 апреля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Илья Аров, старший разработчик в Т1, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Илья будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Илье
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqvXt7qT
6 811
💎Enum как полноценные классы с методами и интерфейсами
Enum в Java — это не просто перечисление констант. Это полноценные классы с конструкторами, методами и поддержкой ООП.
💠 1. Enum с абстрактными методами
public enum FileFormat {
CSV {
public String parse(String data) {
return data.replace(",", ";");
}
},
JSON {
public String parse(String data) {
return "{" + data + "}";
}
};
public abstract String parse(String data);
}
💠 2. Реализация интерфейсов
public interface Formatter {
String format(String text);
}
public enum TextFormat implements Formatter {
UPPERCASE {
public String format(String text) {
return text.toUpperCase();
}
},
LOWERCASE {
public String format(String text) {
return text.toLowerCase();
}
};
}
// Пример вызова
String result = TextFormat.UPPERCASE.format("Hello"); // "HELLO"
💠 3. Состояния и полиморфизм
public enum OrderStatus {
NEW(1) {
public OrderStatus next() {
return PROCESSING;
}
},
PROCESSING(2) {
public OrderStatus next() {
return SHIPPED;
}
},
SHIPPED(3) {
public OrderStatus next() {
return COMPLETED;
}
};
private final int code;
OrderStatus(int code) {
this.code = code;
}
public abstract OrderStatus next();
}
💠 4. Enum в JPA-сущностях
@Entity
public class Order {
@Enumerated(EnumType.STRING)
private OrderStatus status;
}
// Сохраняется как строка "NEW", "PROCESSING" в БД
💠 5. Поиск по значению
public static OrderStatus findByCode(int code) {
return Arrays.stream(OrderStatus.values())
.filter(status -> status.code == code)
.findFirst()
.orElseThrow();
}
⚠️ Опасности:
▸ Перегруженность логикой нарушает принцип SRP
▸ Сложность тестирования из-за статической природы
▸ Ограниченная расширяемость после компиляции
Практические кейсы:
▸ Фабрики объектов с предопределёнными настройками
▸ State Machine для управления состоянием приложения
▸ Конфигурация параметров системы
💠Пример интеграции с Stream API:
public enum MathOperation {
PLUS("+", (a, b) -> a + b),
MINUS("-", (a, b) -> a - b);
private final String symbol;
private final IntBinaryOperator operation;
MathOperation(String symbol, IntBinaryOperator operation) {
this.symbol = symbol;
this.operation = operation;
}
public int apply(int a, int b) {
return operation.applyAsInt(a, b);
}
}
// Использование
int result = MathOperation.PLUS.apply(5, 3); // 8
💠P.S. enum в switch-выражениях
String description = switch (status) {
case NEW -> "Новый заказ";
case PROCESSING -> "В обработке";
case SHIPPED -> "Отправлен";
};
💠Дополнение:
Используйте EnumSet для эффективной работы с группами констант:
EnumSet activeStatuses = EnumSet.of(NEW, PROCESSING);
if (activeStatuses.contains(currentStatus)) {
// Логика для активных статусов
}6 811
Ищем Java специалистов. Релокейт, удалёнка, платим много!
Специально для Вас, собираем лучшие вакансии с прямыми контактами в Telegram на канале @it_match_java. Подпишись чтобы не упустить свой шанс получить лучший оффер!
6 811
🖥 Блоки инициализации в Java
Блоки инициализации позволяют гибко управлять созданием объектов. Вот как их правильно использовать:
💠 Нестатические блоки
Выполняются перед конструктором:
public class Logger {
private String prefix;
{ // Блок инициализации экземпляра (выполняется перед конструктором)
prefix = "[LOG] " + LocalDateTime.now(); // Инициализация префикса с текущей датой/временем
System.out.println("Логгер готов!"); // Сообщение о готовности логгера
}
public Logger() {
System.out.println(prefix + " | Новый объект"); // Вывод информации о создании объекта
}
}
▸ Для чего: предварительная настройка полей, валидация, логирование.
💠 Статические блоки
Срабатывают один раз при загрузке класса:
public class ConfigLoader {
static {
System.out.println("Загружаем конфиги...");
// Здесь можно читать файлы, подключать БД и т.д.
}
}
▸ Для чего: инициализация кэшей, регистрация драйверов, загрузка ресурсов.
📝 Когда что использовать
- Нестатические блоки → простая инициализация полей
- Статические блоки → настройка системных ресурсов
🧬Дополнение:
Для улучшения читаемости кода используйте блоки инициализации для простых операций. Избегайте сложной логики — это может затруднить отладку и понимание приложения.6 811
⚡️ ИИ захватывает рынок. А ты всё ещё смотришь туториалы по Python?
Пока ты открываешь 10-й гайд по Django, другие уже разворачивают модели в проде и оптимизируют пайплайны на Spark.
⚠️ Спойлер: они не умнее тебя. Просто выбрали правильные источники.
😍 Архив Программиста
— твой фундамент: языки, фреймворки, база.
💙 Data Signal
— следующий уровень: Data Science, ML, Big Data.
Вместе — это полный стек навыков, чтобы оставаться в игре. Подписывайся на оба — и стань тем, кого не догонят.
6 811
⌨️ Что такое Project Jigsaw?
До Java 9 весь Java-код (и твой, и JDK) хранился в виде «монолитных» JAR-файлов, и зависимости между ними не контролировались явно. Project Jigsaw решил эту проблему, введя модули, которые:
• Четко определяют, что экспортируется наружу.
• Указывают, от чего зависят.
• Позволяют уменьшить размер приложения (особенно полезно для Java SE Embedded).
• Улучшают безопасность и инкапсуляцию.
Каждый модуль содержит файл
module-info.java, в котором описываются зависимости и экспортируемые пакеты.
➡️ Пример module-info.java:
module com.example.app {
requires java.sql;
exports com.example.app.api;
}
✅ Преимущества модульной системы:
• Четкая структура зависимостей.
• Улучшенная читаемость и поддерживаемость.
• Компиляция и запуск только нужных модулей.
• Инкапсуляция внутренних пакетов (по умолчанию они недоступны извне).6 811
⌨️ Автоупаковка (autoboxing). Правила упаковки примитивных типов в классы-обертки
Автоупаковка - это механизм неявной инициализации объектов классов-оберток (
Byte, Short, Integer, Long, Float, Double, Character, Boolean) значениями соответствующих им исходных примитивных типов (byte, short, int...), без явного использования конструктора класса.
Автоупаковка происходит при прямом присваивании примитива классу-обертке (с помощью оператора =), либо при передаче примитива в параметры метода (типа класса-обертки).
Автоупаковке в классы-обертки могут быть подвергнуты как переменные примитивных типов, так и константы времени компиляции (литералы и final-примитивы). При этом литералы должны быть синтаксически корректными для инициализации переменной исходного примитивного типа.
Автоупаковка переменных примитивных типов требует точного соответствия типа исходного примитива типу класса-обертки. Например, попытка упаковать переменную типа byte в Short, без предварительного явного приведения byte в short вызовет ошибку компиляции.
Автоупаковка констант примитивных типов допускает более широкие границы соответствия. В этом случае компилятор способен предварительно осуществлять неявное расширение/сужение типа примитивов:
✔️ неявное расширение/сужение исходного типа примитива до типа примитива, соответствующего классу-обертке (для преобразования int в Byte, сначала компилятор самостоятельно неявно сужает int к byte)
✔️ автоупаковку примитива в соответствующий класс-обертку. Однако, в этом случае существуют два дополнительных ограничения:
a) присвоение примитива обертке может производится только оператором = (нельзя передать такой примитив в параметры метода без явного приведения типов)
b) тип левого операнда не должен быть старше чем Character, тип правого не должен старше, чем int: допустимо расширение/сужение byte в/из short, byte в/из char, short в/из char и только сужение byte из int, short из int, char из int. Все остальные варианты требуют явного приведения типов).
Дополнительной особенностью целочисленных классов-оберток, созданных автоупаковкой констант в диапазоне -128 ... +127 является то, что они кэшируются JVM. Поэтому такие обертки с одинаковыми значениями будут являться ссылками на один объект.
#java #autoboxing6 811
ИИ-помощника в каждый бизнес!
✨Акция на Битрикс24
Купи годовой тариф Битрикс24 со скидкой - 30% и получи ИИ-помощника на сумму 100 000 рублей бонусом.
Делаем искусственный интеллект доступным каждому бизнесу.❤️
Узнать больше
#реклама 16+
ai-sale.bitrix24.ru
О рекламодателе
6 811
⌨️ Лямбда-выражения и свой кастомный функциональный интерфейс
Для того что бы определить лямбда-выражение, нам нужен функциональный интерфейс. Изобретём свой:
@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
}
Функциональный интерфейс MathOperation содержит один абстрактный метод operate, который принимает два значения типа int и возвращает int. Аннотация @FunctionalInterface указывает на то, что интерфейс предназначен для использования в функциональном программировании и должен содержать только один абстрактный метод. Но аннотация не обязательна.
Использование лямбда-выражения:
public class LambdaExample {
public static void main(String[] args) {
// Реализация интерфейса с помощью лямбда-выражения
MathOperation addition = (a, b) -> a + b;
MathOperation subtraction = (a, b) -> a - b;
MathOperation multiplication = (a, b) -> a * b;
MathOperation division = (a, b) -> a / b;
int x = 10;
int y = 5;
System.out.println("Addition: " + operate(x, y, addition)); // 15
System.out.println("Subtraction: " + operate(x, y, subtraction)); // 5
System.out.println("Multiplication: " + operate(x, y, multiplication)); // 50
System.out.println("Division: " + operate(x, y, division)); // 2
}
// Метод, принимающий MathOperation и применяющий его к данным
private static int operate(int a, int b, MathOperation operation) {
return operation.operate(a, b);
}
}
В нашем примере лямбда-выражения используются для создания экземпляров интерфейса MathOperation для выполнения различных математических операций (сложение, вычитание и т.д.).
Метод operate принимает два целых числа и функциональный интерфейс MathOperation, затем выполняет переданную операцию. В метод в третьем параметре можно передать непосредственно лямбда-выражение, не используя промежуточную переменную.
#java #lambda #FunctionalInterface6 811
Я пожалею об этом, но ладно...
В общем сливаю вам самый топовый источник сервисов, софта, программ, новостей из мира IT.
Если после этого не сможешь обезопасить свой девайс, то ты безнадежен!
Вот ссылка - https://t.me/+zxnnnF0q_wtmZTgy
6 811
☕️ JBCrypt
🔺JBCrypt - это библиотека для безопасного хеширования паролей в Java, реализующая алгоритм bcrypt. Она обеспечивает надежную защиту паролей от атак перебором и радужных таблиц.
💫 Пример: Система регистрации и аутентификации
import org.mindrot.jbcrypt.BCrypt;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class AuthenticationSystem {
private static Map users = new HashMap<>();
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("1. Регистрация");
System.out.println("2. Вход");
System.out.println("3. Выход");
System.out.print("Выберите действие: ");
int choice = scanner.nextInt();
scanner.nextLine(); // Очистка буфера
switch (choice) {
case 1:
register(scanner);
break;
case 2:
login(scanner);
break;
case 3:
System.out.println("До свидания!");
return;
default:
System.out.println("Неверный выбор. Попробуйте снова.");
}
}
}
private static void register(Scanner scanner) {
System.out.print("Введите имя пользователя: ");
String username = scanner.nextLine();
System.out.print("Введите пароль: ");
String password = scanner.nextLine();
String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt());
users.put(username, hashedPassword);
System.out.println("Регистрация успешна!");
}
private static void login(Scanner scanner) {
System.out.print("Введите имя пользователя: ");
String username = scanner.nextLine();
System.out.print("Введите пароль: ");
String password = scanner.nextLine();
if (users.containsKey(username) && BCrypt.checkpw(password, users.get(username))) {
System.out.println("Вход выполнен успешно!");
} else {
System.out.println("Неверное имя пользователя или пароль.");
}
}
}
🛡JBCrypt предоставляет простой и эффективный способ защиты паролей пользователей. Использование этой библиотеки значительно повышает безопасность приложений, работающих с аутентификацией пользователей.6 811
От чего зависит эффективность автотестов?
От их правильного написания и поддерживаемости!
В QA GURU мы учим приручать Java, чтобы ваши автотесты работали, как часы. Вот несколько лайфхаков, о которых мы расскажем на вводном занятии уже завтра (20:00 Мск):
1. Используйте понятные и описательные названия тестов
Названия тестов должны четко отражать их цель. Это упрощает понимание кода всеми членами команды.
Например:
// Хорошо
public void verifyLoginWithValidCredentials() { ... }
// Плохо
public void test1() { ... }
Описательные названия помогают быстро понять, что проверяет тест, без необходимости изучения его внутренней логики.
2. Применяйте Page Object Model (POM)
Page Object Model позволяет отделить логику теста от структуры веб-страницы, что делает код более модульным и удобным для поддержки при изменениях интерфейса.
Пример использования:
// Класс
Page Object
public class LoginPage {
private By usernameField = By. id("username");
private By passwordField = By. id("password");
private By loginButton = By. id("loginBtn");
public void enterUsername(String username) {
driver.findElement(usernameField).sendKeys(username);
}
public void enterPassword(String password) {
driver.findElement(passwordField).sendKeys(password);
}
public void clickLoginButton() {
driver.findElement(loginButton).click();
}
}
// Тестовый сценарий
LoginPage loginPage = new LoginPage(driver);
loginPage.enterUsername("john.doe");
loginPage.enterPassword("password123");
loginPage.clickLoginButton();
POM способствует повторному использованию кода и улучшает читаемость тестов.
3. Используйте параметризацию и data-driven подход
Параметризованные тесты позволяют запускать один и тот же сценарий с различными входными данными, что увеличивает охват тестирования без дублирования кода.
@ ParameterizedTest
@ CsvSource({"john.doe, password123", "jane.smith, test@123"})
public void verifyLogin(String username, String password) {
LoginPage loginPage = new LoginPage(driver);
loginPage.enterUsername(username);
loginPage.enterPassword(password);
loginPage.clickLoginButton();
}
Этот подход делает тесты более гибкими и масштабируемыми.
4. Следуйте принципу AAA (Arrange, Act, Assert)
Структурируйте тесты в три этапа:
Arrange: подготовка данных и окружения.
Act: выполнение действия.
Assert: проверка результата.
Пример:
@ Test
public void testAddition() {
// Arrange
Calculator calculator = new Calculator();
// Act
int result = calculator.add(2, 3);
// Assert
assertEquals(5, result);
}
Этот подход делает тесты более организованными и легко читаемыми.
5. Логирование и отчетность
Добавляйте логирование в тесты для диагностики проблем:
log. info("Entering username: " + username);
log. info("Clicking on the login button");
Интеграция инструментов отчетности (например, Allure) помогает визуализировать результаты тестов и быстро выявлять ошибки.
6. Регулярные ревью кода
Проводите регулярные ревью автотестов для повышения качества кода. Это помогает выявить потенциальные проблемы, улучшить читаемость и обеспечить соблюдение стандартов кодирования.
7. Автоматизация и CI/CD
Используйте инструменты автоматизации (Maven, Gradle) для запуска тестов в рамках CI/CD пайплайнов. Это ускоряет процесс разработки и обеспечивает стабильность приложения на всех этапах.
Хотите узнать больше? Присоединяйтесь завтра (20:00 Мск) к нашему бесплатному открытому уроку!
🔗 Зарегистрируйтесь на первый открытый урок по ссылке.6 811
⌨️ Pattern Matching для instanceof
Начиная с Java 16, проверка типов с помощью
instanceof стала гораздо удобнее благодаря Pattern Matching. Раньше, после проверки объекта на принадлежность к определённому классу, нужно было выполнять явное приведение типа. Теперь это можно сделать в одной строке.
Пример до Java 16:
if (obj instanceof String) {
String str = (String) obj;
System.out.println(str.length());
}
Пример с Pattern Matching:
if (obj instanceof String str) {
System.out.println(str.length());
}
Теперь после instanceof можно сразу же использовать объект нужного типа в коде, что делает программу более читабельной и компактной.
#java #PatternMatching #instanceof6 811
Почему тебе стоит перейти на Go
Для программистов, которые хотят работать над проектами уровня Kubernetes, а не "писать формы"
Я напишу всего 5 причин, но их, на самом деле, больше.
Простота и лаконичность кода Высокая производительность Отличная поддержка конкурентности Широкие возможности для backend-разработки Быстрая компиляция и кроссплатформенность
И это далеко не всё. 2 апреля на вебинаре ты:
— Узнаешь, как переходить с других языков на Go, даже если ты уже прикипел к своему стеку.
— Получишь возможность всего за 2 месяца сменить свой стек и зарабатывать больше.
Спикер вебинара - Дмитрий Березницкий. Chief Technical Officer с 20 летним опытом разработки решений в областях безопасности, блокчейна, финтеха и электронной коммерции, с основным фокусом на рынке США.
https://raise.kata.academy/web_go?utm_source=telegram&utm_medium=telegain&utm_campaign=web_go&utm_content=java_tips_and_tricks&erid=2W5zFGcH3Rz
6 811
☕️ Quartz
Quartz - это мощная библиотека с открытым исходным кодом для планирования и выполнения задач по расписанию в Java-приложениях. Она предоставляет гибкие возможности для определения сложных расписаний выполнения задач и поддерживает кластеризацию.
🌐Пример: Планирование задачи резервного копирования базы данных
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.time.LocalDateTime;
public class BackupSchedulerExample {
public static void main(String[] args) throws SchedulerException {
// Создаем планировщик
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// Определяем задачу
JobDetail job = JobBuilder.newJob(DatabaseBackupJob.class)
.withIdentity("databaseBackupJob", "backupGroup")
.build();
// Создаем триггер для запуска задачи каждый день в 2:00
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("dailyBackupTrigger", "backupGroup")
.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(2, 0))
.build();
// Планируем задачу с триггером
scheduler.scheduleJob(job, trigger);
// Запускаем планировщик
scheduler.start();
System.out.println("Планировщик резервного копирования запущен.");
System.out.println("Следующее резервное копирование запланировано на: "
+ trigger.getNextFireTime());
// Оставляем планировщик работать
try {
Thread.sleep(60000); // Ждем 1 минуту для демонстрации
} catch (InterruptedException e) {
e.printStackTrace();
}
// Останавливаем планировщик
scheduler.shutdown();
}
// Класс, представляющий задачу резервного копирования
public static class DatabaseBackupJob implements Job {
@Override
public void execute(JobExecutionContext context) {
System.out.println("Выполняется резервное копирование базы данных: "
+ LocalDateTime.now());
// Здесь был бы реальный код для резервного копирования
}
}
}
🔐Quartz предоставляет надежное решение для планирования и выполнения задач в Java-приложениях. Его гибкость позволяет реализовывать сложные сценарии планирования, от простых периодических задач до сложных расписаний с учетом праздников, временных зон и других факторов.6 811
👍 Тренд 2025 года — развитие без лишних затрат!
Зачем платить за дорогостоящие ресурсы, если все, что тебе нужно, уже собрано в Telegram? Программисты уже переходят на новый уровень, получая доступ к лучшим материалам без единого вложения:
👩💻 JavaScript 👩💻 React
👩💻 Python 👩💻 Docker
👩💻 Java 🖼️ Spring
👩💻 C# 👩💻 Game Dev
👩💻 С/С++ 👩💻 DevOps
👣 GoLang 🖼️ Redis
👩💻 Kotlin 👩💻 Mob Dev
🖼️ PHP 🖥 SQL
🖼️ Swift 👩💻 Kubernetes
В 2025 году все доступные ресурсы уже здесь, бесплатно! Подписывайся и будь в тренде, не тратя деньги на платные подписки 👍
6 811
☕️Библиотека Java: MapStruct
🗂MapStruct — это генератор кода для маппинга между Java-бинами, который создает реализации mapper-ов на этапе компиляции.🗂Основные преимущества:
1. 🗣Автоматический маппинг полей с одинаковыми именами 2. 🗣Высокая производительность (нет рефлексии в runtime) 3. 🗣Поддержка сложных преобразований 4. 🗣Интеграция с Spring и CDI🗂Пример использования:
@Mapper(componentModel = "spring")
public interface UserMapper {
@Mapping(target = "fullName", expression = "java(user.getFirstName() + \" \" + user.getLastName())")
@Mapping(target = "status", constant = "ACTIVE")
UserDto toDto(User user);
@Mapping(target = "firstName", source = "fullName.split(\" \")[0]")
@Mapping(target = "lastName", source = "fullName.split(\" \")[1]")
User toEntity(UserDto dto);
}
🗂Ключевые особенности:
-💬 Генерация чистого Java-кода без зависимостей -💬 Поддержка коллекций и потоков -💬 Преобразование типов -💬 Работа с вложенными объектами -💬 Кастомные методы маппинга🗣Интеграция с Spring:
@Service
@RequiredArgsConstructor
public class UserService {
private final UserMapper userMapper;
public UserDto createUser(UserRequest request) {
User user = userMapper.toEntity(request);
// бизнес-логика
return userMapper.toDto(user);
}
}6 811
☕️Лямбда-выражения и Stream API
💻Лямбда-выражения и Stream API кардинально изменили подход к обработке данных в Java, позволив писать более декларативный и выразительный код.
🗂Пример без лямбд:
List<String> names = Arrays.asList("John", "Alice", "Bob");
Collections.sort(names, new Comparator() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
🗂С лямбда-выражением:
List<String> names = Arrays.asList("John", "Alice", "Bob");
names.sort((a, b) -> a.compareTo(b));
🔵Stream API позволяет выполнять сложные операции над коллекциями:
List<String> filteredNames = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
🗂Ключевые преимущества:
1.⏺ Упрощение работы с коллекциями 2.⏺ Возможность цепочечных вызовов методов 3.⏺ Параллельная обработка через parallelStream() 4.⏺ Ленивое выполнение операций
🗂Примеры: 1.🔅 Фильтрация и преобразование:
List<Product> expensiveProducts = products.stream()
.filter(p -> p.getPrice() > 1000)
.map(p -> p.withDiscount(0.1))
.collect(Collectors.toList());
2.🟡 Группировка данных:
Map<String, List<Employ>> employeesByDepartment = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
3.💬 Статистические операции:
IntSummaryStatistics stats = salaries.stream()
.mapToInt(Integer::intValue)
.summaryStatistics();
🗂Особенности работы:
- 💬Stream не изменяет исходную коллекцию - 💬Многие операции возвращают новый Stream - 💬Терминальные операции завершают цепочку - 💬Оптимизированная работа с памятью
6 811
☕️Фишка Java: Optional для Null-Safety
⚙️Работа с null-значениями традиционно была источником ошибок в Java. Класс Optional предоставляет более элегантный способ обработки потенциально отсутствующих значений.
💬Традиционный подход:
User user = getUserById(id);
if (user != null) {
Address address = user.getAddress();
if (address != null) {
String city = address.getCity();
if (city != null) {
System.out.println(city.toUpperCase());
}
}
}
💻С использованием Optional:
Optional.ofNullable(getUserById(id))
.map(User::getAddress)
.map(Address::getCity)
.ifPresent(city -> System.out.println(city.toUpperCase()));
💻Основные методы Optional:
1.⏺ ofNullable() - создает Optional из значения, которое может быть null 2.⏺ map() - преобразует значение, если оно присутствует 3.⏺ orElse() - предоставляет значение по умолчанию 4.⏺ ifPresent() - выполняет действие, если значение есть 5.⏺ orElseThrow() - бросает исключение, если значения нет
🗂Примеры: 1.🔐 Безопасное получение вложенных свойств:
String cityName = Optional.ofNullable(order)
.map(Order::getCustomer)
.map(Customer::getAddress)
.map(Address::getCity)
.orElse("Unknown");
2. 🗂Комбинация нескольких Optional:
Optional<Double> totalPrice = Optional.ofNullable(order1)
.flatMap(o1 -> Optional.ofNullable(order2)
.map(o2 -> o1.getPrice() + o2.getPrice()));
3. 🗂Работа с коллекциями:
List<String> names = Optional.ofNullable(userList)
.orElse(Collections.emptyList())
.stream()
.map(User::getName)
.filter(Objects::nonNull)
.collect(Collectors.toList());
🗂Преимущества использования Optional:
1.⏺ Явное указание на возможность отсутствия значения 2.⏺ Устранение проверок на null в коде 3.⏺ Четкая цепочка преобразований 4.⏺ Более читаемый и выразительный код
