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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Полезные методы Collections

1️⃣ Collections.min() и Collections.max()

List<Integer> list = Arrays.asList(10, 5, 30, 7);
System.out.println(Collections.min(list)); // 5
System.out.println(Collections.max(list)); // 30



2️⃣ Collections.fill() — заполнение списка одним значением

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Collections.fill(list, "X");
System.out.println(list); // [X, X, X]



3️⃣ Collections.replaceAll() — замена значений

List<String> list = new ArrayList<>(Arrays.asList("яблоко", "груша", "яблоко"));
Collections.replaceAll(list, "яблоко", "банан");
System.out.println(list); // [банан, груша, банан]



4️⃣ Collections.frequency() — подсчет вхождений элемента

List<String> list = Arrays.asList("A", "B", "A", "C", "A");
int count = Collections.frequency(list, "A");
System.out.println(count); // 3


#java #Collections #min #max #fill #replaceAll #frequency
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍156
⚙️ Compact Strings – как Java экономит память на строках?

В Java 9 появилась Compact Strings, уменьшающая использование памяти на 30-40%.

✔️ Как это работает?

🟢 До Java 9 каждая String хранила char[], занимающий 2 байта на символ.
🟢 В Java 9+ String хранит byte[], если все символы – ASCII.

📌 Как включить/выключить?

-XX:+CompactStrings // Включить (по умолчанию)
-XX:-CompactStrings // Выключить


💡 Совет: Если работаете с огромным количеством строк (логирование, JSON), Compact Strings может существенно снизить нагрузку на память.

#java #strings #memoryoptimization
Please open Telegram to view this post
VIEW IN TELEGRAM
👍171
🛠 Object.finalize() устарел! Как правильно освобождать ресурсы?

Метод finalize() объявлен устаревшим в Java 9 и удалён в Java 18, так как он ненадёжный и медленный.

📌 Как освобождать ресурсы правильно?

🟢 Используйте try-with-resources для Closeable объектов:
try (FileInputStream fis = new FileInputStream("file.txt")) {
// Работа с файлом
}


🟢 Для кастомных классов используйте AutoCloseable:
class MyResource implements AutoCloseable {
@Override
public void close() {
System.out.println("Ресурс закрыт");
}
}


💡 Совет: Если ваш объект использует ресурсы (файлы, сокеты, соединения) – реализуйте AutoCloseable.

#java #finalize #autocloseable
Please open Telegram to view this post
VIEW IN TELEGRAM
👍121
🔥 java.lang.Record vs Lombok @Value – что лучше?

Многие используют Lombok для DTO, но с Java 14 появился record. Стоит ли переходить?

🤔 Чем record лучше Lombok?

🟢 Автоматически создаёт toString(), equals(), hashCode().
🟢 Immutable без аннотаций.
🟢 Улучшенная поддержка в JVM и JIT.

📌 Сравнение синтаксиса:


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

// Lombok
@Value
public class User {
String name;
int age;
}


💡 Совет: Используйте record, если вам не нужен полный функционал Lombok – код будет чище.

#java #record #lombok #bestpractices
Please open Telegram to view this post
VIEW IN TELEGRAM
👍151🤔1
🔍 JVM Warm-up – почему Java работает медленно при старте?

➡️ Проблема:

JVM использует JIT-компилятор, но оптимизация занимает время. Это приводит к медленному запуску.

📌 Решение 1: предварительная компиляция (AOT, GraalVM)

jaotc --output=app.aot MyApp.class
java -XX:AOTLibrary=app.aot MyApp


📌 Решение 2: заранее прогревать код

for (int i = 0; i < 10000; i++) {
someMethod(); // Прогреваем JIT-компилятор
}


#java #jvm #performance
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥2❤‍🔥1👏1🤯1
🔄 StructuredTaskScope — это класс, появившийся в Java 21 в рамках проекта Loom, который помогает управлять группами фоновых задач в многопоточной среде. Он предоставляет удобный механизм для управления задачами в рамках структурированного параллелизма (Structured Concurrency).

📌 Для чего нужен StructuredTaskScope?

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

✔️ Преимущества StructuredTaskScope

🟢Простота кода – избавляет от ручного управления Future, CompletableFuture и ExecutorService.
🟢Безопасность – если одна задача падает, можно отменить другие.
🟢Эффективность – интеграция с виртуальными потоками позволяет выполнять множество задач с минимальными накладными расходами.

➡️ Пример:


import java.util.concurrent.*;

public class StructuredTaskScopeExample {

public static void main(String[] args) throws InterruptedException, ExecutionException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// Запускаем две параллельные задачи
var task1 = scope.fork(() -> fetchDataFromAPI("API 1"));
var task2 = scope.fork(() -> fetchDataFromAPI("API 2"));

// Дожидаемся завершения (или отмены в случае ошибки)
scope.join();
scope.throwIfFailed(); // Выбросит исключение, если одна из задач завершилась с ошибкой

// Получаем результаты
String result1 = task1.get();
String result2 = task2.get();

System.out.println("Result 1: " + result1);
System.out.println("Result 2: " + result2);
}
}

private static String fetchDataFromAPI(String apiName) throws InterruptedException {
Thread.sleep(1000); // Имитация задержки запроса
if (Math.random() > 0.8) throw new RuntimeException(apiName + " failed!"); // Имитация ошибки
return apiName + " response";
}
}


#java #concurrency #structuredconcurrency
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14
🚀 ZGC vs G1GC – какой GC лучше?

В Java 17 появился ZGC – он обещает минимальную задержку. Но лучше ли он G1GC?

✔️ Сравнение:


+------+----------+-----------+----------+
| GC | Паузы | Поддержка | CPU |
| | | хипа | нагрузка |
+------+----------+-----------+----------+
| G1GC | До 200ms | До 16ТБ | Средняя |
| ZGC | <10ms | До 16ТБ | Низкая |
+------+----------+-----------+----------+


📌 Как включить?
-XX:+UseZGC


💡 Совет: ZGC идеально подходит для low-latency приложений, но G1GC лучше сбалансирован для большинства случаев.

#java #gc #performance
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15
⌨️ О чем говорит ключевое слово final?

Модификатор final может применяться к переменным, параметрам методов, полям и методам класса или самим классам.

✔️ Класс не может иметь наследников;

✔️ Метод не может быть переопределен в классах наследниках;

✔️ Поле не может изменить свое значение после инициализации;

✔️ Параметры методов не могут изменять своё значение внутри метода;

✔️ Локальные переменные не могут быть изменены после присвоения им значения.

#java #final
Please open Telegram to view this post
VIEW IN TELEGRAM
👍152🔥1
⚡️ JSON в Java (Jackson vs Gson vs JSON-B)

Работа с JSON – частая задача, но Jackson, Gson и JSON-B работают по-разному. Какой выбрать?

⚙️ Скорость сериализации (от самого быстрого):

Jackson – самый быстрый (использует ByteBuffer).
Gson – медленнее, так как использует Reflection.
JSON-B – стандартный API, но проигрывает по производительности.

✔️ Пример с использованием Jackson:


ObjectMapper objectMapper = new ObjectMapper();

// Объект → JSON (сериализация)
Person person = new Person("Alice", 30);
String json = objectMapper.writeValueAsString(person);
System.out.println("Jackson Serialized: " + json);

// JSON → Объект (десериализация)
Person deserialized = objectMapper.readValue(json, Person.class);
System.out.println("Jackson Deserialized: " + deserialized.name + ", " + deserialized.age);


✔️ Пример с использованием Gson:


Gson gson = new Gson();

// Объект → JSON (сериализация)
Person person = new Person("Bob", 25);
String json = gson.toJson(person);
System.out.println("Gson Serialized: " + json);

// JSON → Объект (десериализация)
Person deserialized = gson.fromJson(json, Person.class);
System.out.println("Gson Deserialized: " + deserialized.name + ", " + deserialized.age);


✔️ Пример с использованием JSON-B:


Jsonb jsonb = JsonbBuilder.create();

// Объект → JSON (сериализация)
Person person = new Person("Charlie", 35);
String json = jsonb.toJson(person);
System.out.println("JSON-B Serialized: " + json);

// JSON → Объект (десериализация)
Person deserialized = jsonb.fromJson(json, Person.class);
System.out.println("JSON-B Deserialized: " + deserialized.name + ", " + deserialized.age);


💡 Совет: Используйте Jackson для high-performance API, но если важен стандарт – выбирайте JSON-B.

#java #json #jackson #performance
Please open Telegram to view this post
VIEW IN TELEGRAM
👍123🔥3🤔1
👀Как применить Valhalla?

❗️Проект Valhalla: будущее Java с инлайн-классами

❇️Инлайн-классы (или value-классы) представляют собой ключевую часть проекта Valhalla, который значительно изменяет подход к организации данных в Java. Основная идея заключается в объединении производительности примитивов с гибкостью объектов, что позволяет создавать легковесные структуры данных без накладных расходов на размещение в куче.

👾Основные особенности инлайн-классов:

1. Отсутствие идентичности объекта. Инлайн-классы не имеют ссылочной идентичности, то есть сравнение через оператор "==" проверяет содержимое, а не ссылки.
2. 🟢Плоская структура памяти. Данные хранятся компактно, без указателей, что улучшает производительность за счет кэширования.
3. 🔹Zero-Cost Abstraction. Использование инлайн-классов не добавляет накладных расходов по сравнению с примитивами.

Пример использования инлайн-класса:
Рассмотрим класс Point,который представляет координаты на плоскости:

public primitive class Point {
private final int x;
private final int y;

public Point(int x, int y) {
this.x = x;
this.y = y;
}

public int getX() {
return x;
}

public int getY() {
return y;
}
}

Ключевое слово primitive указывает, что это инлайн-класс. Его экземпляры хранятся как примитивы, без заголовков и указателей.

Преимущества инлайн-классов:

1.💠 Улучшенная производительность массивов. Массив Point[] будет хранить данные в плоском виде, а не как массив ссылок на объекты.
2.📉 Снижение накладных расходов на сборку мусора. Инлайн-объекты не требуют частого вмешательства сборщика мусора (GC).
3. 🛡Оптимизация локальности данных. Данные хранятся компактно, что уменьшает количество промахов кэша.

Пример работы с массивом:

Point[] points = new Point[100];
for (int i = 0; i < points.length; i++) {
points[i] = new Point(i, i * 2);
}
System.out.println(points[50].getX()); // 50

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

🚫Ограничения инлайн-классов:

1.❇️ Инлайн-классы неизменяемы, все поля должны быть final.
2. Они не могут содержать ссылочные циклы, например, ссылки на самих себя или другие объекты с циклическими зависимостями.
3. 💤В настоящее время находятся в экспериментальной стадии начиная с Java 19.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥41
⌨️ Что же это такое Records и sealed classes?

🔹Комбинация records и sealed classes позволяет создавать строгие и безопасные модели данных с ограничениями на наследование. Это особенно полезно при реализации доменных моделей.

Records, введенные в Java 14, предоставляют лаконичный способ создания неизменяемых классов данных. Sealed classes, появившиеся в Java 17, позволяют ограничивать наследование.

🫥 Пример реализации системы управления платежами:

public sealed interface PaymentMethod permits CreditCard, BankTransfer, PayPal {
    boolean isValid();
    void process();
}

public record CreditCard(String cardNumber, String expiryDate, String cvv) implements PaymentMethod {
    @Override
    public boolean isValid() {
        return cardNumber != null && cardNumber.length() == 16
               && expiryDate != null && cvv != null;
    }
   
    @Override
    public void process() {
        System.out.println("Processing credit card payment");
    }
}

public record BankTransfer(String accountNumber, String bankCode) implements PaymentMethod {
    @Override
    public boolean isValid() {
        return accountNumber != null && bankCode != null;
    }
   
    @Override
    public void process() {
        System.out.println("Processing bank transfer");
    }
}

public record PayPal(String email) implements PaymentMethod {
    @Override
    public boolean isValid() {
        return email != null && email.contains("@");
    }
   
    @Override
    public void process() {
        System.out.println("Processing PayPal payment");
    }
}

public record Payment(UUID id, BigDecimal amount, PaymentMethod method) {
    public boolean processPayment() {
        if (method.isValid()) {
            method.process();
            return true;
        }
        return false;
    }
}

Преимущества:

1. Типобезопасность: Компилятор гарантирует, что только определенные классы могут реализовывать PaymentMethod.
2. Неизменяемость: Records обеспечивают неизменяемость данных.
3. Краткость кода: Records автоматически генерируют методы.

Пример использования:

public void handlePayment(Payment payment) {
    if (payment.processPayment()) {
        switch (payment.method()) {
            case CreditCard cc -> handleCreditCardPayment(cc);
            case BankTransfer bt -> handleBankTransferPayment(bt);
            case PayPal pp -> handlePayPalPayment(pp);
        }
    } else {
        handleFailedPayment(payment);
    }
}

Этот подход особенно полезен для моделирования бизнес-доменов и реализации паттерна "Состояние".
Он позволяет создавать более безопасный и поддерживаемый код.
Please open Telegram to view this post
VIEW IN TELEGRAM
10❤‍🔥2
👾Захват стека вызовов через StackWalker

🔸StackWalker, введенный в Java 9, предоставляет эффективный способ работы с текущим стеком вызовов. Это мощный инструмент для логирования, отладки и анализа производительности.

Основные преимущества StackWalker:

1. 🟢Эффективность: StackWalker использует ленивую загрузку фреймов стека.
2. 🟢Гибкость: API предоставляет различные методы для работы со стеком.
3. 🟢Настраиваемость: Можно указать, какие фреймы включать в обход.

🟣Пример использования StackWalker:

public class StackWalkerExample {
    public static void main(String[] args) {
        method1();
    }

    private static void method1() {
        method2();
    }

    private static void method2() {
        method3();
    }

    private static void method3() {
        StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
        walker.forEach(frame -> {
            System.out.println("Класс: " + frame.getClassName() +
                               ", Метод: " + frame.getMethodName() +
                               ", Строка: " + frame.getLineNumber());
        });
    }
}

Более сложный пример с фильтрацией и обработкой стека:

public class AdvancedStackWalkerExample {
    public static void main(String[] args) {
        logMethodCall();
    }

    private static void logMethodCall() {
        StackWalker walker = StackWalker.getInstance(EnumSet.of(
            StackWalker.Option.RETAIN_CLASS_REFERENCE,
            StackWalker.Option.SHOW_REFLECT_FRAMES
        ));

        List callStack = walker.walk(stream ->
            stream.filter(frame -> !frame.getClassName().startsWith("java.lang"))
                  .map(frame -> frame.getClassName() + "." + frame.getMethodName())
                  .limit(5)
                  .collect(Collectors.toList())
        );

        System.out.println("Стек вызовов (до 5 методов, исключая java.lang):");
        callStack.forEach(System.out::println);
    }
}


В заключение, StackWalker предоставляет мощный и эффективный способ работы со стеком вызовов, улучшая производительность и гибкость кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍101
⌨️ Чем отличается процесс от потока?

Процесс — экземпляр программы во время выполнения, независимый объект, которому выделены системные ресурсы (например, процессорное время и память). Каждый процесс выполняется в отдельном адресном пространстве: один процесс не может получить доступ к переменным и структурам данных другого. Если процесс хочет получить доступ к чужим ресурсам, необходимо использовать межпроцессное взаимодействие. Это могут быть конвейеры, файлы, каналы связи между компьютерами и многое другое.

Для каждого процесса ОС создает так называемое «виртуальное адресное пространство», к которому процесс имеет прямой доступ. Это пространство принадлежит процессу, содержит только его данные и находится в полном его распоряжении. Операционная система же отвечает за то, как виртуальное пространство процесса проецируется на физическую память.

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

#java #process #thread
Please open Telegram to view this post
VIEW IN TELEGRAM
👍153🔥2
⌨️ Почему String неизменяемый класс?

Есть несколько преимуществ в неизменности строк:

✔️ Пул строк возможен только потому, что строка неизменяемая, таким образом виртуальная машина сохраняет больше свободного места в Heap, поскольку разные строковые переменные указывают на одну и ту же переменную в пуле. Если бы строка была изменяемой, то интернирование строк не было бы возможным, потому что изменение значения одной переменной отразилось бы также и на остальных переменных, ссылающихся на эту строку.

✔️ Если строка будет изменяемой, тогда это станет серьезной угрозой безопасности приложения. Например, имя пользователя базы данных и пароль передаются строкой для получения соединения с базой данных и в программировании сокетов реквизиты хоста и порта передаются строкой. Так как строка неизменяемая, её значение не может быть изменено, в противном случае злоумышленник может изменить значение ссылки и вызвать проблемы в безопасности приложения.

✔️ Неизменяемость позволяет избежать синхронизации: строки безопасны для многопоточности и один экземпляр строки может быть совместно использован различными потоками.

✔️ Строки используются classloader и неизменность обеспечивает правильность загрузки класса.

✔️ Поскольку строка неизменяемая, её hashCode() кэшируется в момент создания и нет необходимости рассчитывать его снова. Это делает строку отличным кандидатом для ключа в HashMap т.к. его обработка происходит быстрее.

#java #string #immutable
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍6
Всё не слава богу
😁23👍43🤣3
☕️ Возвращение пустых коллекций вместо null

Возвращение пустых коллекций вместо null-это рекомендуемый подход для методов, возвращающих коллекции. Он упрощает обработку данных, предотвращает ошибки и делает код более предсказуемым.

Преимущества

1. Улучшение читаемости: Код становится проще, так как не нужно проверять результат на null.
2. Предотвращение NullPointerException: Исключается вероятность ошибок, связанных с доступом к null.
3.Соответствие принципу наименьшего удивления: Методы всегда возвращают коллекцию, даже если она пуста.
4. Эффективность: Пустые коллекции создаются один раз и переиспользуются благодаря реализации через паттерн Singleton.
5. Совместимость с функциональным программированием: Пустые коллекции легко интегрируются в стримы и другие функциональные конструкции.

Пример:

public class CacheService {
    private final Map<String, List<Object>> cache = new ConcurrentHashMap<>();

    public List<Object> getCachedValues(String key) {
        return cache.getOrDefault(key, Collections.emptyList());
    }

    public void addToCache(String key, Object value) {
        cache.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
    }
}


❗️ Метод Collections.emptyList() является частью стандартной библиотеки Java (java.util.Collections). Он реализован через паттерн Singleton для повышения эффективности и безопасности.

Использование пустых коллекций вместо null делает код более устойчивым и предсказуемым. Это особенно важно в сложных многопоточных приложениях или системах с большим количеством взаимосвязанных компонентов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍133
Varargs (Variable Arguments List, изменяющийся список аргументов) — это способ создания методов, которые могут принимать произвольное количество аргументов одного типа (от нуля и более). Данная возможность появилась в JDK 5.

Запись вида Object... args и есть varargs.

При этом три точки после типа указывают, что метод в качестве аргумента может принимать как массив, так и любую последовательность аргументов, записанных через запятую, которая все равно преобразуется в одномерный массив - «под капотом» компилятор на уровне байт-кода неявно заменяет переданную последовательность массивом. Уже в методе аргумент varargs используется как одномерный массив.

Альтернативой varargs является перегрузка методов или передача в метод массива значений.

Varargs был создан с целью упрощения работы программиста, удобства и краткости кода.

📌 В качестве ограничения любой метод может использовать varargs только в единственном числе и строго последним аргументом.
🔥8👍5
⌨️ Какой хеш-код имеет null?

null не имеет хеш-кода, потому что null не является объектом. Однако, при использовании null в структурах данных, таких как HashMap или HashSet, применяется специальная логика:

➡️ Что происходит с null в HashMap и HashSet?

✔️ В HashMap ключ null всегда попадает в первый бакет (bucket 0).
✔️ В HashSet (который использует HashMap внутри) null также хранится в этом же бакете.
✔️ Проверки выполняются в Objects.hashCode(), который для null всегда возвращает 0.

➡️ Пример:


System.out.println(Objects.hashCode(null)); // 0


📌 Вывод: null не имеет собственного хеш-кода, но в хеш-структурах ему назначается 0.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🔥21
⌨️ Diamond-оператор (<>) упрощает работу с обобщениями (Generics), позволяя компилятору автоматически выводить тип.

➡️ До Java 7 (без <>):

List<String> list = new ArrayList<String>(); // Приходилось дублировать <String>


➡️ С Java 7+ (с <>):

List<String> list = new ArrayList<>(); // Компилятор сам выводит <String>


Преимущества <>:
Уменьшает дублирование кода
Улучшает читаемость
Работает с любыми обобщёнными классами

Итог: Diamond-оператор делает код чище и проще, автоматизируя вывод типов!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍141🔥1👀1
⌨️ Double-brace инициализация - техника создания и инициализации коллекций в одном выражении, используя анонимный внутренний класс.

Пример:


List<String > planets = new ArrayList<>() {{
add ("Mercury");
add ("Venus");
add ("Earth");
add ("Mars");
add ("Jupiter");
add ("Saturn");
add ("Uranus") ;
add ("Neptune");
}};


Преимущества:

1. Краткость
2. Читаемость
3. Удобство для небольших коллекций

🚫Недостатки:

1. Создание анонимного класса (увеличение потребления памяти)
2. Скрытая ссылка (возможные утечки памяти)
3. Ограничения с final классами
4. Несовместимость с оператором diamond
5. Потенциальное влияние на производительность
6. Считается антипаттерном

🔻Альтернативы:

1. ☕️Java 8 Stream API:

List<String> planets = Stream.of("Mercury", "Venus", "Earth")
.collect(Collectors.toList());


2. ☕️Java 9+:
List<String> planets = List.of("Mercury", "Venus", "Earth");


3.🖨Конструктор копирования:

List<Integer> list = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(2, 3, 5)));


Несмотря на удобство, double-brace инициализация считается антипаттерном из-за проблем с производительностью и возможных утечек памяти.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥1🌭1