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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Метод Stream.distinct()

Если у вас есть поток, который может содержать повторяющиеся элементы, используйте операцию distinct(), чтобы удалить их.


var list = Arrays.asList(1, 2, 3, 3, 4, 5, 5);
var distinctList = list.stream()
.distinct()
.collect(Collectors.toList());
// distinctList: [1, 2, 3, 4, 5]
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🚀 Реактивное программирование с помощью Project Reactor

Реактивное программирование — это новый подход к созданию асинхронных и масштабируемых приложений. Project Reactor — библиотека для Java, которая делает этот процесс простым и эффективным.

🔍 Что такое Project Reactor?

Project Reactor предоставляет инструменты для работы с потоками данных, основанные на спецификации Reactive Streams. Это дает возможность обрабатывать асинхронные события, используя:

1. Mono: асинхронный поток, который возвращает 0 или 1 элемент. Идеален для единичных значений.

2. Flux: поток, который может вернуть 0, 1 или много элементов. Отлично подходит для работы с коллекциями данных.

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

🏎️ Высокая производительность: Неблокирующая модель усиливает эффективность использования ресурсов.

🛠️ Простой в обработке ошибок: Реактивные методы делают управление ошибками интуитивным.

📜 Читабельный код: Операторы позволяют писать более чистый и понятный код.
5
⌨️ Простой пример использования Project Reactor, который демонстрирует основы работы с Mono и Flux.


import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class ProjectReactorExample {
public static void main(String[] args) {
// Пример с Mono
Mono<String> monoExample = Mono.just("Hello, Reactor!");
monoExample
.map(String::toUpperCase) // Преобразуем строку в верхний регистр
.subscribe(System.out::println); // Подписываемся и выводим результат

// Пример с Flux
Flux<Integer> fluxExample = Flux.just(1, 2, 3, 4, 5);
fluxExample
.filter(num -> num % 2 == 0) // Фильтруем четные числа
.map(num -> num * num) // Возводим в квадрат
.subscribe(System.out::println); // Подписываемся и выводим результат
}
}


🔍 Что происходит в коде?

1. Mono:
- Создаем экземпляр Mono с помощью Mono.just(), передавая строку.
- Используем метод map(), чтобы преобразовать строку в верхний регистр.
- Подписываемся на Mono с помощью subscribe, который выводит результат.

2. Flux:
- Создаем экземпляр Flux с числовыми значениями от 1 до 5.
- Фильтруем четные числа с помощью filter().
- Применяем map(), чтобы возвести каждое четное число в квадрат.
- Подписываемся на Flux и выводим результат.
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍41
public class Quest {
public static final Quest INSTANCE = new Quest();
private final int yearsAgo;
private static final int CURRENT_YEAR = Calendar.getInstance().get(Calendar.YEAR);

private Quest() {
yearsAgo = CURRENT_YEAR - 2000;
}

public int yearsAgo() {
return yearsAgo;
}

public static void main(String[] args) {
System.out.println(INSTANCE.yearsAgo());
}
}
👍1
Что выведет код?
Anonymous Quiz
42%
24
16%
-2000
8%
0
33%
<Ошибка компиляции>
🎉3👍1
🌱 Spring SpEL (Spring Expression Language) — это мощный язык выражений, предоставляемый фреймворком Spring. Он используется для динамической обработки данных, управления конфигурацией и вычисления значений в runtime. SpEL позволяет обращаться к свойствам объектов, вызывать методы, работать с коллекциями, выполнять арифметические и логические операции, а также взаимодействовать с бинами Spring.

Основные возможности SpEL:

✔️ Обращение к свойствам: person.name

✔️Вызов методов: person.getName()

✔️ Работа с коллекциями: фильтрация и проекция (list.?[property > 10]).

✔️ Логические и арифметические операции: age > 18 && hasLicense

✔️ Доступ к бинам Spring: @beanName.method()

Простой пример:

import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class SpELExample {
public static void main(String[] args) {
ExpressionParser parser = new SpelExpressionParser();

// Пример вычисления простого выражения
String expression = "'Hello, Spring SpEL!'.toUpperCase()";
String result = parser.parseExpression(expression).getValue(String.class);

System.out.println(result); // Вывод: HELLO, SPRING SPEL!
}
}


Использование в аннотациях:

@Component
public class MyBean {
@Value("#{T(java.lang.Math).random() * 100}")
private double randomValue;

@Value("#{systemProperties['user.name']}")
private String userName;

public void printValues() {
System.out.println("Random Value: " + randomValue);
System.out.println("User Name: " + userName);
}
}


✔️ T(java.lang.Math).random() — вызов статического метода Math.random().

✔️ systemProperties['user.name'] — доступ к системным свойствам.

Использование с коллекциями:

import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.util.Arrays;
import java.util.List;

public class CollectionExample {
public static void main(String[] args) {
ExpressionParser parser = new SpelExpressionParser();

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Фильтрация списка
List<Integer> filteredNumbers = (List<Integer>) parser.parseExpression(
"#numbers.?[#this > 2]").getValue(new StandardEvaluationContext(), numbers);

System.out.println(filteredNumbers); // Вывод: [3, 4, 5]
}
}


SpEL является удобным инструментом для внедрения динамического поведения и вычислений в приложениях Spring.
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍93
public class Quest {
public static void main(String[] args) {
String s = null;
System.out.println(s instanceof String);
}
}
👍2
public class Quest {
public static void greet() {
System.out.println("Hello world!");
}

public static void main(String[] args) {
Quest q = null;
q.greet();
}
}
👍3
👍3🎉3😁21
⌨️ EnumMap — это реализация Map, которая использует в качестве ключей исключительно Enum.

Внутренне EnumMap использует массив для хранения значений, где индекс массива соответствует порядковому номеру (ordinal()) элемента перечисления. Это делает его быстрее, чем хэш-таблицы (HashMap) и более экономным по памяти.

EnumMap хранит ключи в порядке их объявления в перечислении, что отличает его от большинства других Map (кроме LinkedHashMap).

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

🔍 Пример:

import java.util.EnumMap;

enum Action {
START, STOP, PAUSE
}

public class EnumMapExample {
public static void main(String[] args) {
EnumMap<Action, Runnable> actionMap = new EnumMap<>(Action.class);

// Определяем поведение для каждого значения Enum
actionMap.put(Action.START, () -> System.out.println("Starting the process..."));
actionMap.put(Action.STOP, () -> System.out.println("Stopping the process..."));
actionMap.put(Action.PAUSE, () -> System.out.println("Pausing the process..."));

// Пример вызова
Action currentAction = Action.START;
actionMap.get(currentAction).run();
}
}


#Java #EnumMap
Please open Telegram to view this post
VIEW IN TELEGRAM
👍195
⌨️ Как работает IdentityHashMap

IdentityHashMap — это необычная реализация Map, которая использует сравнение по ссылкам (==) вместо стандартного метода equals().

В IdentityHashMap два ключа считаются равными только если это один и тот же объект (сравнение по ссылкам).

📌 Пример:

java
import java.util.IdentityHashMap;
import java.util.Map;

public class IdentityHashMapExample {
public static void main(String[] args) {
Map<String, String> map = new IdentityHashMap<>();

String key1 = new String("key");
String key2 = new String("key");

map.put(key1, "Value 1");
map.put(key2, "Value 2");

System.out.println(map); // Выведет обе пары: {key=Value 1, key=Value 2}
}
}


key1 и key2 — это разные объекты, даже если их строки одинаковы.

Когда использовать?

1️⃣ Кэширование: если нужно различать объекты с одинаковыми данными.

2️⃣ Оптимизация: для низкоуровневой работы с объектами, где важна ссылка, а не значение.

3️⃣ Специфические задачи: при разработке компиляторов, интерпретаторов или для отслеживания уникальных объектов.

💡 Ограничение:
IdentityHashMap не гарантирует порядок элементов и редко используется в стандартных задачах. Это инструмент для узкоспециализированных случаев!

#Java #IdentityHashMap
Please open Telegram to view this post
VIEW IN TELEGRAM
👍101
⌨️ WeakHashMap: когда удаление происходит само собой

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

Если ключ в WeakHashMap становится недостижимым (нет сильных ссылок), он удаляется сборщиком мусора.

Это делает WeakHashMap полезной для реализации кэшей и других структур, где нужно избегать утечек памяти.

📌 Пример:

java
import java.util.WeakHashMap;

public class WeakHashMapExample {
public static void main(String[] args) {
WeakHashMap<Object, String> map = new WeakHashMap<>();

Object key = new Object();
map.put(key, "Value");

System.out.println("Before GC: " + map); // Ключ и значение есть

key = null; // Убираем сильную ссылку на объект
System.gc(); // Вызываем сборку мусора

System.out.println("After GC: " + map); // Ключ и значение исчезли
}
}


Пока объект-ключ доступен, пара ключ-значение остаётся в WeakHashMap.
Как только ключ становится недоступным, он автоматически удаляется сборщиком мусора.

Когда использовать?

1️⃣ Кэширование: для хранения данных, которые можно восстановить, если они удалены.

2️⃣ Маппинг вспомогательных данных: например, привязка метаданных к объектам, где их удаление важно.

💡 Совет:
Не используйте WeakHashMap для данных, которые критически важны — сборщик мусора может удалить их в любой момент!

#Java #WeakHashMap
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🤷‍♂21👎1🤩1
⌨️ Как управлять порядком элементов в LinkedHashMap?

LinkedHashMap — это реализация Map, которая сохраняет порядок добавления элементов. Но что, если нужен порядок по использованию (LRU-кэш)? LinkedHashMap справится и с этим!

Порядок добавления (по умолчанию):

java
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
public static void main(String[] args) {
Map<Integer, String> map = new LinkedHashMap<>();

map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");

System.out.println(map); // {1=One, 2=Two, 3=Three}
}
}


Порядок использования:
Передайте accessOrder = true в конструктор.

java
import java.util.LinkedHashMap;
import java.util.Map;

public class LRUExample {
public static void main(String[] args) {
Map<Integer, String> map = new LinkedHashMap<>(16, 0.75f, true);

map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");

map.get(2); // Используем ключ 2
System.out.println(map); // {1=One, 3=Three, 2=Two}
}
}


Можно переопределить метод removeEldestEntry() для автоматического удаления старых записей.


@Override
protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {
return size() > 3; // Удалять записи, если их больше 3
}


#Java #LinkedHashMap #LRU
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥2
import java.util.*;

public class Quest {
private static Random rnd = new Random();
public static void main(String[] args) {
StringBuffer word = null;
switch(rnd.nextInt(2)) {
case 1: word = new StringBuffer('P');
case 2: word = new StringBuffer('G');
default: word = new StringBuffer('M');
}
word.append('a');
word.append('i');
word.append('n');
System.out.println(word);
}
}
👍3
Что выведет код?
Anonymous Quiz
27%
Main
32%
Pain или Main
23%
Pain или Gain
18%
ain
😭15🎉3
😁10🤣6👎1💯1
⌨️ Параллельное программирование и CompletableFuture

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

Стандартный метод работы с потоками может быть сложным и запутанным. CompletableFuture — более удобный и мощный инструмент, который упрощает асинхронное программирование.

✍️ Пример: Выполнение задач параллельно с использованием CompletableFuture

import java.util.concurrent.CompletableFuture;

public class AsyncExample {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();

CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
sleep(2000);
return "Результат задачи 1";
});

CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
sleep(3000);
return "Результат задачи 2";
});

CompletableFuture<String> combined = task1.thenCombine(task2, (result1, result2) -> result1 + " & " + result2);

// Ожидаем завершения всех задач и получаем общий результат
combined.thenAccept(result -> {
long endTime = System.currentTimeMillis();
System.out.println("Общий результат: " + result);
System.out.println("Время выполнения: " + (endTime - startTime) + " мс");
});

combined.join(); // Дождёмся завершения наших задач
}

private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


🔧 Что происходит в коде?
1️⃣ Мы запускаем две задачи, каждая из которых выполняется асинхронно.
2️⃣ Используем метод thenCombine, чтобы объединить результаты двух задач.
3️⃣ Когда обе задачи завершены, выводим общий результат и время выполнения.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍112
⌨️ Files.walkFileTree(): мощный инструмент для работы с файловой системой

Files.walkFileTree() из пакета java.nio.file позволяет рекурсивно обходить дерево каталогов и выполнять сложные операции. Это гибкий и удобный способ работать с файловой системой, включая чтение, обработку, копирование или удаление файлов.

🔍 Как это работает?
1️⃣ Реализуется интерфейс FileVisitor, который определяет действия для каждой операции.
2️⃣ Можно обрабатывать файлы и директории на каждом этапе обхода.

📌 Пример: удаление дерева каталогов


import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

public class WalkFileTreeExample {
public static void main(String[] args) throws IOException {
Path startPath = Paths.get("example_directory");

Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("Deleting file: " + file);
Files.delete(file); // Удаляем файл
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
System.out.println("Deleting directory: " + dir);
Files.delete(dir); // Удаляем директорию после удаления её содержимого
return FileVisitResult.CONTINUE;
}
});
}
}


🔗 Ключевые методы FileVisitor:
visitFile() — вызывается для каждого файла.
postVisitDirectory() — вызывается после обхода содержимого директории.
preVisitDirectory() — вызывается перед входом в директорию.
visitFileFailed() — обрабатывает ошибки доступа.

Когда использовать?
1️⃣ Для удаления, копирования или архивирования файлов/папок.
2️⃣ Для поиска файлов по сложным критериям.
3️⃣ Для выполнения массовых операций с файлами (изменение атрибутов, анализ).

💡 Совет: Используйте SimpleFileVisitor, чтобы переопределять только нужные методы, а не реализовать весь интерфейс FileVisitor.

#Java #Files #FileVisitor
Please open Telegram to view this post
VIEW IN TELEGRAM
👍61
⌨️ Collectors.teeing(): две операции над одним потоком

С появлением Java 12 Collectors.teeing() стал удобным инструментом для объединения двух независимых операций над потоком. Этот коллектор позволяет выполнять две разные операции над данными и объединять их результат с помощью функции-объединителя.

🔍 Как это работает?
1️⃣ Указываем два коллектора для операций.
2️⃣ Задаём функцию, которая объединит результаты этих операций.

📌 Пример: Найдём сумму и среднее списка чисел.


import java.util.List;
import java.util.stream.Collectors;

public class TeeingExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5);

var result = numbers.stream().collect(
Collectors.teeing(
Collectors.summingInt(Integer::intValue), // Первая операция: сумма
Collectors.averagingInt(Integer::intValue), // Вторая операция: среднее
(sum, avg) -> "Sum: " + sum + ", Average: " + avg // Объединение результатов
)
);

System.out.println(result); // Вывод: Sum: 15, Average: 3.0
}
}


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

Когда использовать?
1️⃣ Для выполнения нескольких независимых операций над данными потока.
2️⃣ Если нужно объединить результаты этих операций.

💡 Совет:
Collectors.teeing() особенно полезен, когда результаты независимых операций логически связаны. Например, для расчёта статистики или агрегации данных.

#Java #Streams #Collectors #teeing
Please open Telegram to view this post
VIEW IN TELEGRAM
👍112