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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Неограниченным wildcard <?>

В Java <?> называется неограниченным wildcard. Он обозначает, что параметр типа может быть любым, то есть неизвестным на этапе компиляции. Это удобно, когда метод или класс работают с обобщёнными типами, но конкретный тип элемента не важен.

Например, выражение List<?> означает список, элементы которого могут быть любого типа. Такой подход позволяет писать более универсальный и гибкий код, но при этом накладывает ограничения: мы не можем добавлять новые элементы в коллекцию, поскольку компилятор не знает конкретный тип элементов, чтобы обеспечить безопасность типов.

✔️ Прием метода, работающего с любым типом списка


import java.util.List;

public class WildcardExample {
public static void printList(List<?> list) {
for (Object element : list) { // Элементы можно читать как Object
System.out.println(element);
}
}

public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3);
List<String> strList = List.of("A", "B", "C");

printList(intList); // Вывод: 1 2 3
printList(strList); // Вывод: A B C
}
}


Здесь List<?> позволяет передавать любой тип списка, но мы можем безопасно читать только как Object.

Ограничение на добавление элементов


public static void addElement(List<?> list) {
// list.add("Hello"); // Ошибка компиляции!
}


#java #wildcard
Please open Telegram to view this post
VIEW IN TELEGRAM
👍181🔥1
⌨️ Wildcard. Использование с extends (ограничение сверху)

Если мы хотим работать только с числами (Number и его потомками), можно использовать ? extends Number:

import java.util.List;

public class WildcardExample {
public static double sumNumbers(List<? extends Number> list) {
double sum = 0;
for (Number num : list) {
sum += num.doubleValue();
}
return sum;
}

public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3);
List<Double> doubleList = List.of(1.1, 2.2, 3.3);

System.out.println(sumNumbers(intList)); // Вывод: 6.0
System.out.println(sumNumbers(doubleList)); // Вывод: 6.6
}
}


🔹 ? extends Number означает, что list может быть списком любого подкласса Number (Integer, Double, Float и т. д.).
🔹 Это позволяет безопасно читать значения, но не добавлять новые (аналогично <?>).

#java #wildcard
Please open Telegram to view this post
VIEW IN TELEGRAM
👍101
⌨️ Wildcard. Использование с super (ограничение снизу)

Иногда нужно работать с базовыми типами (например, добавлять в List<? super Integer> только Integer и его предков):

import java.util.List;
import java.util.ArrayList;

public class WildcardExample {
public static void addNumbers(List<? super Integer> list) {
list.add(10);
list.add(20);
}

public static void main(String[] args) {
List<Number> numberList = new ArrayList<>();
addNumbers(numberList);
System.out.println(numberList); // Вывод: [10, 20]
}
}


🔹 ? super Integer означает, что list может быть списком Integer или его родительских классов (Number, Object).
🔹 Это позволяет безопасно добавлять Integer, но при чтении придется использовать Object.

#java #wildcard
Please open Telegram to view this post
VIEW IN TELEGRAM
👍91
⌨️ Класс Formatter

java.util.Formatter позволяет создавать отформатированные строки по аналогии с printf() в C.

Formatter может форматировать числа, дату, время, выравнивать текст, управлять пробелами и отступами, а так же работать с локалями.


import java.util.Formatter;

public class FormatterExample {
public static void main(String[] args) {
try (Formatter formatter = new Formatter()) {
formatter.format("Привет, %s! Тебе %d лет.", "Андрей", 25);
System.out.println(formatter);
// Привет, Андрей! Тебе 25 лет.
}
}
}


Можно не просто форматировать строки, но и записывать их в файл:

import java.io.FileNotFoundException;
import java.util.Formatter;

public class FileWriteExample {
public static void main(String[] args) throws FileNotFoundException {
try (Formatter formatter = new Formatter("output.txt")) {
formatter.format("Имя: %s, Возраст: %d%n", "Алиса", 30);
}
}
}


Теперь в файле output.txt будет строка:
Имя: Алиса, Возраст: 30

#java #Formatter
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍32👏2
😁29🤣13👍75
🤔 Почему ThreadLocal может привести к утечкам памяти?

ThreadLocal – удобный способ хранения данных в потоке, но может привести к утечкам памяти.

➡️ Проблема:

Потоки из ThreadPool не удаляются сразу после завершения работы.
Если ThreadLocal не очищается вручную, объект остаётся в памяти, даже если он больше не нужен.

📌 Решение: всегда вызывайте remove()

ThreadLocal<MyClass> threadLocal = ThreadLocal.withInitial(MyClass::new);

try {
MyClass obj = threadLocal.get();
// Логика
} finally {
threadLocal.remove(); // Очищаем объект
}


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

#java #threadlocal #memoryleak
Please open Telegram to view this post
VIEW IN TELEGRAM
👍152
Как избежать проблем с Parallel Stream?

Использование parallelStream() может замедлить программу, если не учитывать его особенности.

➡️ Проблемы:

🟢 Не стоит использовать с маленькими коллекциями – накладные расходы на потоки выше, чем выгода.
🟢 Будьте осторожны с изменяемыми переменными в forEach().

Ошибка: некорректное изменение общей переменной

int[] sum = {0};
list.parallelStream().forEach(i -> sum[0] += i); // Потенциальная ошибка!


📌 Решение: использовать reduce()

int sum = list.parallelStream().reduce(0, Integer::sum);


💡 Совет: parallelStream() эффективен, если объём данных большой и нет конкурентного доступа.

#java #parallelstream #performance
Please open Telegram to view this post
VIEW IN TELEGRAM
👍131
⌨️ Интерфейсы Closeable и AutoCloseable

Интерфейсы Closeable и AutoCloseable предназначены для управления ресурсами, которые нужно явно закрывать после использования, например, потоки ввода-вывода, соединения с базами данных и т. д. Однако у них есть некоторые различия.

1️⃣ AutoCloseable появился в Java 7 в связи с введением try-with-resources, это базовый интерфейс для всех ресурсов, которые могут быть автоматически закрыты.

В AutoCloseable определен метод:

void close() throws Exception;

То есть, метод close() может выбрасывать любое исключение (Exception).

2️⃣ Closeable наследует AutoCloseable, более специфичен и предназначен в основном для потоков ввода-вывода (I/O).

В Closeable метод close() может выбрасывать только IOException.

#java #Closeable #AutoCloseable
Please open Telegram to view this post
VIEW IN TELEGRAM
👍151
Ну что там у вас с пет-проектами?)
😁35😭5🤣3🔥2👍1
🚀 Foreign Function & Memory API – замена JNI в Java 22

В Java 22 появился Foreign Function & Memory API, который позволяет взаимодействовать с C-библиотеками без JNI.

🤔 Зачем он нужен?

Безопаснее – нет Unsafe.
Проще – не нужно писать C-обёртки.
Быстрее – меньше накладных расходов.

📌 Пример вызова метода strlen из библиотеки C:


static long invokeStrlen(String s) throws Throwable {

try (Arena arena = Arena.ofConfined()) {

// Allocate off-heap memory and
// copy the argument, a Java string, into off-heap memory
MemorySegment nativeString = arena.allocateUtf8String(s);

// Link and call the C function strlen

// Obtain an instance of the native linker
Linker linker = Linker.nativeLinker();

// Locate the address of the C function signature
SymbolLookup stdLib = linker.defaultLookup();
MemorySegment strlen_addr = stdLib.find("strlen").get();

// Create a description of the C function
FunctionDescriptor strlen_sig =
FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);

// Create a downcall handle for the C function
MethodHandle strlen = linker.downcallHandle(strlen_addr, strlen_sig);

// Call the C function directly from Java
return (long)strlen.invokeExact(nativeString);
}
}


💡 Совет: Используйте этот API для работы с нативными библиотеками вместо JNI.

#java #foreignapi #native
Please open Telegram to view this post
VIEW IN TELEGRAM
👍91
⌨️ Полезные методы Collections

1️⃣ Collections.sort() — сортировка списка

import java.util.*;

public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList("Вика", "Андрей", "Сергей");
Collections.sort(names);
System.out.println(names); // [Андрей, Вика, Сергей]
}
}

📌 Работает с Comparable. Можно передавать Comparator для кастомной сортировки.


2️⃣ Collections.reverse() — реверс списка

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Collections.reverse(numbers);
System.out.println(numbers); // [5, 4, 3, 2, 1]



3️⃣ Collections.shuffle() — перемешивание элементов

List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
Collections.shuffle(nums);
System.out.println(nums); // случайный порядок, например [3, 1, 5, 2, 4]

💡 Полезно для перемешивания карт, вопросов в викторине и т. д.

#java #Collections #sort #reverse #shuffle
Please open Telegram to view this post
VIEW IN TELEGRAM
👍91🔥1
⌨️ Чтение и запись файла с помощью класса Files

Чтение всего файла в список строк (readAllLines)

import java.nio.file.*;
import java.io.IOException;
import java.util.List;

public class Main {
public static void main(String[] args) throws IOException {
Path path = Paths.get("example.txt");
List<String> lines = Files.readAllLines(path);
lines.forEach(System.out::println);
}
}

📌 Читает весь файл в List<String>, удобно для небольших файлов.

Запись в файл (write)

List<String> lines = List.of("Первая строка", "Вторая строка");
Files.write(Paths.get("output.txt"), lines);

📌 Если файла нет — создаст, если есть — перезапишет.

Добавление в файл (без перезаписи):

Files.write(Paths.get("output.txt"), lines, StandardOpenOption.APPEND);


#java #Files #readAllLines #write
Please open Telegram to view this post
VIEW IN TELEGRAM
👍181
⌨️ Метод Stream.reduce()

Метод reduce() используется для агрегирования (свёртки) элементов стрима в одно значение. Это мощный инструмент для вычислений, таких как сумма, произведение, конкатенация строк и т. д.

1️⃣ T reduce(T identity, BinaryOperator<T> accumulator)

🟢identity – начальное значение (например, 0 для суммы, 1 для произведения).
🟢accumulator – функция, которая объединяет элементы.

Пример: сумма чисел

List<Integer> numbers = List.of(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, Integer::sum);
System.out.println(sum); // 15


2️⃣ reduce(accumulator) (без начального значения)


Optional<T> reduce(BinaryOperator<T> accumulator)


📌 Здесь возвращается Optional<T>, потому что стрим может быть пустым.

Пример: наибольшее число

Optional<Integer> max = numbers.stream().reduce(Integer::max);
max.ifPresent(System.out::println); // 5


3️⃣ reduce(identity, accumulator, combiner) (для параллельных потоков)


<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)


Пример: длина всех строк в списке

List<String> words = List.of("Java", "Stream", "Reduce");
int totalLength = words.parallelStream()
.reduce(0, (sum, word) -> sum + word.length(), Integer::sum);
System.out.println(totalLength); // 16


Здесь:
🟢sum + word.length() – считает длину строк,
🟢Integer::sum – объединяет результаты.

💡 Совет: Для простых случаев (сумма, максимум) используйте sum(), max(), count(), а reduce() – для сложных операций.

#java #reduce
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍183
⌨️ Полезные методы 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