Java for Beginner
672 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Что выведет код?

public class ArrayExample {
public static void main(String[] args) {
int[] array = new int[]{1, 2, 3, 4, 5};
int sum = 0;

for (int i = 0; i < array.length; i++) {
if (i % 2 == 0) {
sum += array[i];
} else {
sum -= array[i];
}
}

System.out.println(sum);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
10%
4
0%
5
10%
-2
80%
3
Мы все когда-то начинали с Basic😂

https://t.me/Java_for_beginner_dev

#Mems
CompletableFuture в Java

CompletableFuture — это расширение Future, которое предоставляет мощные средства для работы с асинхронными задачами. Он позволяет легко комбинировать и связывать асинхронные операции, использовать методы обратного вызова (callback) и работать с исключениями.

Создание и выполнение задач с помощью CompletableFuture
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {

public static void main(String[] args) {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 42;
});

System.out.println("Doing something else while the task is running...");

try {
Integer result = future.get();
System.out.println("Task completed with result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}


Методы thenApply, thenAccept и thenRun

thenApply(Function): Применяет функцию к результату завершенного CompletableFuture и возвращает новый CompletableFuture.
thenAccept(Consumer): Принимает потребителя для обработки результата завершенного CompletableFuture.
thenRun(Runnable): Выполняет действие после завершения CompletableFuture, не используя его результат.


Пример использования:
import java.util.concurrent.CompletableFuture;

public class CompletableFutureChainingExample {

public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 42;
}).thenApply(result -> result * 2)
.thenAccept(result -> System.out.println("Result: " + result))
.thenRun(() -> System.out.println("Task completed!"));
}
}


Обработка исключений

CompletableFuture предоставляет методы для обработки исключений, такие как exceptionally, handle и whenComplete.

Пример обработки исключений:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExceptionHandlingExample {

public static void main(String[] args) {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (true) {
throw new RuntimeException("Something went wrong!");
}
return 42;
}).exceptionally(ex -> {
System.out.println("Exception: " + ex.getMessage());
return -1;
});

try {
Integer result = future.get();
System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}

#Java #Training #Multithreading #Medium
Комбинирование CompletableFuture

Методы thenCombine и thenCompose позволяют комбинировать несколько CompletableFuture.

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

import java.util.concurrent.CompletableFuture;

public class CompletableFutureCombineExample {

public static void main(String[] args) {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 42;
});

CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 24;
});

CompletableFuture<Integer> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + result2);

try {
System.out.println("Combined result: " + combinedFuture.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}


Пример использования thenCompose:
import java.util.concurrent.CompletableFuture;

public class CompletableFutureComposeExample {

public static void main(String[] args) {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 42;
});

CompletableFuture<Integer> composedFuture = future.thenCompose(result ->
CompletableFuture.supplyAsync(() -> result * 2)
);

try {
System.out.println("Composed result: " + composedFuture.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}


#Java #Training #Multithreading #Medium
Многопоточность в Java: volatile и Immutable Classes

Volatile

Ключевое слово volatile в Java используется для обозначения переменных, которые могут быть изменены различными потоками. Переменная, объявленная как volatile, гарантирует, что все потоки будут читать ее актуальное значение из основной памяти, а не из кэша процессора. Это помогает избежать некоторых проблем с видимостью, которые могут возникнуть в многопоточных приложениях.

Пример использования volatile
public class VolatileExample {
private volatile boolean running = true;

public void start() {
new Thread(() -> {
while (running) {
System.out.println("Thread is running...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread stopped.");
}).start();
}

public void stop() {
running = false;
}

public static void main(String[] args) {
VolatileExample example = new VolatileExample();
example.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
example.stop();
}
}

В этом примере поток проверяет значение переменной running и останавливается, когда она становится false. Использование volatile гарантирует, что изменения переменной running будут видны всем потокам.



Immutable Classes

Иммутабельные (неизменяемые) классы — это классы, состояния объектов которых не могут быть изменены после создания. Они особенно полезны в многопоточной среде, так как обеспечивают безопасность потоков (thread-safety) без необходимости использования синхронизации.

Пример неизменяемого класса
public final class ImmutablePerson {
private final String name;
private final int age;

public ImmutablePerson(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public int getAge() {
return age;
}

@Override
public String toString() {
return "ImmutablePerson{name='" + name + "', age=" + age + "}";
}

public static void main(String[] args) {
ImmutablePerson person = new ImmutablePerson("John", 30);
System.out.println(person);
// person.setName("Doe"); // This would cause a compile error
}
}


В этом примере класс ImmutablePerson является неизменяемым, потому что все его поля final, и они инициализируются только один раз в конструкторе.

Преимущества неизменяемых классов

Потокобезопасность: Нет необходимости в синхронизации, так как состояние объекта не может быть изменено после создания.
Простота использования: Меньше ошибок, связанных с изменением состояния.
Упрощенная разработка: Легче проектировать и отлаживать.


#Java #Training #Multithreading #Medium #Volatile #Immutable_Classes
Что выведет код?

public class VariableChallenge {
public static void main(String[] args) {
int x = 5;
final int y;

if (x > 3) {
y = 10;
} else {
y = 20;
}

x = x + y;

int z = x > 15 ? x * 2 : x / 2;

System.out.println(z);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
10%
30
0%
25
20%
15
70%
7
Долбанные разработчики 😂

https://t.me/Java_for_beginner_dev

#Mems
Многопоточность в Java: Deadlock

Deadlock (взаимная блокировка) — это состояние, при котором два или более потоков блокируют друг друга, ожидая освобождения ресурсов, занятых друг другом. Это приводит к тому, что ни один из потоков не может продолжать выполнение.
public class DeadlockExample {

private final Object lock1 = new Object();
private final Object lock2 = new Object();

public void method1() {
synchronized (lock1) {
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}

public void method2() {
synchronized (lock2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock1) {
System.out.println("Thread 2: Holding lock 2 & 1...");
}
}
}

public static void main(String[] args) {
DeadlockExample example = new DeadlockExample();

Thread thread1 = new Thread(example::method1);
Thread thread2 = new Thread(example::method2);

thread1.start();
thread2.start();
}
}

В этом примере возникает deadlock, потому что thread1 захватывает lock1 и ждет lock2, в то время как thread2 захватывает lock2 и ждет lock1. Таким образом, оба потока оказываются в состоянии взаимной блокировки.

Способы предотвращения Deadlock

Иерархия блокировок: Всегда захватывайте ресурсы в определенном порядке.
Тайм-ауты: Используйте методы с тайм-аутами для захвата блокировок, такие как tryLock из ReentrantLock.
Избегайте вложенных блокировок: Старайтесь минимизировать количество вложенных блокировок.


Пример с использованием tryLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;

public class DeadlockAvoidanceExample {

private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();

public void method1() {
try {
if (lock1.tryLock(50, TimeUnit.MILLISECONDS)) {
try {
System.out.println("Thread 1: Holding lock 1...");
Thread.sleep(50);
if (lock2.tryLock(50, TimeUnit.MILLISECONDS)) {
try {
System.out.println("Thread 1: Holding lock 1 & 2...");
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public void method2() {
try {
if (lock2.tryLock(50, TimeUnit.MILLISECONDS)) {
try {
System.out.println("Thread 2: Holding lock 2...");
Thread.sleep(50);
if (lock1.tryLock(50, TimeUnit.MILLISECONDS)) {
try {
System.out.println("Thread 2: Holding lock 2 & 1...");
} finally {
lock1.unlock();
}
}
} finally {
lock2.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
DeadlockAvoidanceExample example = new DeadlockAvoidanceExample();

Thread thread1 = new Thread(example::method1);
Thread thread2 = new Thread(example::method2);

thread1.start();
thread2.start();
}
}

В этом примере tryLock используется для попытки захвата блокировок с тайм-аутом, что предотвращает возникновение deadlock.

#Java #Training #Multithreading #Medium #Deadlock
Многопоточность в Java: Пул потоков

Пул потоков (Thread Pool) — это механизм управления коллекцией потоков, предназначенный для выполнения задач. Потоки в пуле повторно используются для выполнения нескольких задач, что позволяет сократить накладные расходы на создание и уничтожение потоков и повысить производительность многопоточных приложений.

Зачем нужен пул потоков?

Улучшение производительности: Создание нового потока — дорогостоящая операция. Пул потоков позволяет избежать этих накладных расходов, повторно используя уже существующие потоки.
Контроль над количеством потоков: Пул потоков позволяет ограничить максимальное количество одновременно работающих потоков, что предотвращает исчерпание ресурсов системы.
Упрощение управления задачами: Пул потоков предоставляет удобные методы для отправки задач на выполнение, что упрощает управление многопоточными задачами.


Создание пула потоков

В Java для работы с пулом потоков используется класс ExecutorService, который предоставляет методы для управления потоками и выполнения задач. Воспользоваться готовыми реализациями можно с помощью класса Executors.

Пример создания пула потоков с фиксированным числом потоков
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadPoolExample {

public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);

for (int i = 0; i < 5; i++) {
int taskId = i;
executorService.submit(() -> {
System.out.println("Task " + taskId + " is running in thread " + Thread.currentThread().getName());
try {
Thread.sleep(2000); // Симуляция долгой задачи
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task " + taskId + " completed");
});
}

executorService.shutdown();
}
}


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



Виды пулов потоков

FixedThreadPool: Пул с фиксированным числом потоков. Новый поток не создается, если все потоки заняты, до тех пор, пока один из них не освободится.
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);


CachedThreadPool: Пул, который создает потоки по мере необходимости, но переиспользует старые потоки, если они доступны. Подходит для выполнения большого количества коротких задач.
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();


SingleThreadExecutor: Пул с единственным потоком, выполняющий задачи последовательно.
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();


ScheduledThreadPool: Пул, который позволяет выполнять задачи с задержкой или периодически.
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);


#Java #Training #Multithreading #Medium
Варианты ответа:
Anonymous Quiz
80%
3
0%
4
0%
5
20%
7
Что выведет код?

public class StringChallenge {
public static void main(String[] args) {
String str1 = "Java";
String str2 = new String("Java");
String str3 = "Ja" + "va";
String str4 = str2.intern();

boolean result1 = (str1 == str2);
boolean result2 = (str1 == str3);
boolean result3 = (str1 == str4);
boolean result4 = str1.equals(str2);

int sum = (result1 ? 1 : 0) + (result2 ? 1 : 0) + (result3 ? 1 : 0) + (result4 ? 1 : 0);

System.out.println(sum);
}
}


#Tasks
По-любому у каждого так😉

https://t.me/Java_for_beginner_dev

#Mems
Многопоточность в Java: ExecutorService

ExecutorService — это интерфейс, который предоставляет методы для управления жизненным циклом потоков и для выполнения задач. Он является частью фреймворка java.util.concurrent и предоставляет гибкие способы работы с потоками.


Основные методы ExecutorService

submit(Runnable task): Отправляет задачу на выполнение и возвращает объект Future, представляющий эту задачу.
submit(Callable<T> task): Отправляет задачу, возвращающую результат, на выполнение и возвращает объект Future.
invokeAll(Collection<? extends Callable<T>> tasks): Выполняет все задачи из коллекции и возвращает список объектов Future.
invokeAny(Collection<? extends Callable<T>> tasks): Выполняет все задачи из коллекции и возвращает результат одной из успешно завершенных задач.
shutdown(): Начинает плавное завершение работы пула, позволяя выполнению текущих задач завершиться.
shutdownNow(): Пытается немедленно завершить выполнение всех задач.


Пример использования submit
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class SubmitExample {

public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);

Callable<Integer> task1 = () -> {
Thread.sleep(1000);
return 10;
};

Callable<Integer> task2 = () -> {
Thread.sleep(2000);
return 20;
};

Future<Integer> future1 = executorService.submit(task1);
Future<Integer> future2 = executorService.submit(task2);

try {
System.out.println("Result of task1: " + future1.get());
System.out.println("Result of task2: " + future2.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}

executorService.shutdown();
}
}


Пример использования invokeAll и invokeAny
public class InvokeExample {

public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);

List<Callable<Integer>> tasks = Arrays.asList(
() -> {
Thread.sleep(1000);
return 1;
},
() -> {
Thread.sleep(2000);
return 2;
},
() -> {
Thread.sleep(3000);
return 3;
}
);

try {
List<Future<Integer>> results = executorService.invokeAll(tasks);
for (Future<Integer> result : results) {
System.out.println("Result: " + result.get());
}

Integer anyResult = executorService.invokeAny(tasks);
System.out.println("First completed task result: " + anyResult);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}

executorService.shutdown();
}
}


Управление завершением ExecutorService

Правильное завершение ExecutorService важно для предотвращения утечек ресурсов и корректного завершения программы.

shutdown(): Начинает плавное завершение. Новые задачи не принимаются, но уже отправленные задачи продолжают выполнение.
executorService.shutdown();


shutdownNow(): Пытается немедленно завершить все задачи, возвращает список задач, которые не были начаты.
List<Runnable> notExecutedTasks = executorService.shutdownNow();


awaitTermination(long timeout, TimeUnit unit): Ожидает завершения всех задач в течение указанного времени.

try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}


#Java #Training #Multithreading #Medium #ExecutorService
Concurrency

Concurrency (параллельность) — это способность программы выполнять несколько задач одновременно. В контексте Java, это включает использование многопоточности и синхронизации для обеспечения корректного выполнения параллельных операций.

Коллекции и многопоточность

Стандартные коллекции, такие как ArrayList, HashMap, HashSet и другие, не являются потокобезопасными. Это означает, что если несколько потоков одновременно выполняют операции чтения и записи с этими коллекциями, могут возникнуть проблемы, такие как:


Несогласованность данных: Данные могут быть повреждены или потеряны.
Исключения времени выполнения: Например, ConcurrentModificationException.

Для решения этих проблем в Java были введены потокобезопасные коллекции из пакета java.util.concurrent.

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

Пример использования ConcurrentHashMap
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {

public static void main(String[] args) {
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();

// Добавление элементов в карту
concurrentMap.put("One", 1);
concurrentMap.put("Two", 2);
concurrentMap.put("Three", 3);

// Создание потоков для параллельного чтения и записи
Thread writerThread = new Thread(() -> {
for (int i = 4; i <= 6; i++) {
concurrentMap.put("Number " + i, i);
System.out.println("Added: Number " + i);
try {
Thread.sleep(100); // Симуляция задержки
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

Thread readerThread = new Thread(() -> {
for (int i = 1; i <= 6; i++) {
System.out.println("Value for Number " + i + ": " + concurrentMap.get("Number " + i));
try {
Thread.sleep(150); // Симуляция задержки
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

writerThread.start();
readerThread.start();

try {
writerThread.join();
readerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


В этом примере ConcurrentHashMap используется для параллельных операций чтения и записи. Поток writerThread добавляет элементы в карту, в то время как поток readerThread считывает значения из карты. Благодаря использованию ConcurrentHashMap данные остаются согласованными, и исключения времени выполнения не возникают.

Основные методы ConcurrentHashMap

put(K key, V value): Добавляет пару ключ-значение в карту.
get(Object key): Возвращает значение, связанное с указанным ключом.
remove(Object key): Удаляет пару ключ-значение из карты.
replace(K key, V value): Заменяет значение, связанное с указанным ключом, на новое значение.
computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction): Если ключ отсутствует в карте, вычисляет значение и добавляет его в карту.


#Java #Training #Multithreading #Medium
Что выведет код?

public class AlgorithmChallenge {
public static void main(String[] args) {
int[] arr = {5, 3, 8, 6, 2};
int result = mysteriousFunction(arr);
System.out.println(result);
}

public static int mysteriousFunction(int[] arr) {
int n = arr.length;
int sum = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (arr[i] > arr[j]) {
sum += arr[i] - arr[j];
}
}
}
return sum;
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
0%
3
10%
7
10%
21
80%
18
0%
25
Просто ChatGPT не дали доступ к оружию🙈

https://t.me/Java_for_beginner_dev

#Mems
Продвинутые методы ConcurrentHashMap

ConcurrentHashMap предоставляет дополнительные методы для более тонкого управления данными и выполнения атомарных операций.

Пример использования computeIfAbsent
import java.util.concurrent.ConcurrentHashMap;

public class ComputeIfAbsentExample {

public static void main(String[] args) {
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();

// Добавление элементов в карту
concurrentMap.put("One", 1);
concurrentMap.put("Two", 2);

// Использование computeIfAbsent для добавления значения, если ключ отсутствует
concurrentMap.computeIfAbsent("Three", key -> 3);
concurrentMap.computeIfAbsent("One", key -> 10); // Это значение не будет добавлено, так как ключ уже существует

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


Использование forEach и reduce

ConcurrentHashMap поддерживает методы для параллельной обработки данных, такие как forEach и reduce.

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

import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;

public class ForEachExample {

public static void main(String[] args) {
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("One", 1);
concurrentMap.put("Two", 2);
concurrentMap.put("Three", 3);

// Параллельная обработка элементов карты
concurrentMap.forEach(1, (key, value) -> {
System.out.println("Key: " + key + ", Value: " + value);
});
}
}


Пример использования reduce
import java.util.concurrent.ConcurrentHashMap;

public class ReduceExample {

public static void main(String[] args) {
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("One", 1);
concurrentMap.put("Two", 2);
concurrentMap.put("Three", 3);

// Параллельное суммирование значений карты
int sum = concurrentMap.reduceValues(1, Integer::sum);
System.out.println("Sum of values: " + sum); // Output: Sum of values: 6
}
}


Примеры использования ConcurrentHashMap в реальных задачах

Пример 1: Подсчет количества слов
import java.util.concurrent.ConcurrentHashMap;

public class WordCountExample {

public static void main(String[] args) {
ConcurrentHashMap<String, Integer> wordCounts = new ConcurrentHashMap<>();
String[] words = {"apple", "banana", "apple", "orange", "banana", "apple"};

for (String word : words) {
wordCounts.merge(word, 1, Integer::sum);
}

System.out.println(wordCounts); // {apple=3, banana=2, orange=1}
}
}


Пример 2: Кэширование вычислений
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

public class ComputationCacheExample {

private final ConcurrentHashMap<Integer, String> cache = new ConcurrentHashMap<>();

public String compute(Integer key, Function<Integer, String> computation) {
return cache.computeIfAbsent(key, computation);
}

public static void main(String[] args) {
ComputationCacheExample example = new ComputationCacheExample();

Function<Integer, String> computation = key -> {
try {
Thread.sleep(1000); // Симуляция долгого вычисления
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Result for " + key;
};

System.out.println(example.compute(1, computation)); // Вычисление и кэширование
System.out.println(example.compute(1, computation)); // Использование закэшированного значения
}
}


#Java #Training #Multithreading #Medium
Аннотации в Java

Аннотации в Java — это метаданные, которые добавляются к коду для предоставления дополнительной информации. Они могут быть использованы компилятором, инструментами разработки и во время выполнения (через рефлексию). Аннотации не изменяют логики программы, но могут влиять на её поведение.

Основные встроенные аннотации

@ Override: Указывает, что метод переопределяет метод суперкласса.
@ Deprecated: Обозначает, что элемент (метод, класс, поле) устарел и не рекомендуется к использованию.
@ SuppressWarnings: Подавляет указанные предупреждения компилятора.
@ SafeVarargs: Обозначает, что метод с переменным числом аргументов не выполняет потенциально небезопасных операций с varargs.
@ FunctionalInterface: Указывает, что интерфейс является функциональным и содержит только один абстрактный метод.


Примеры использования встроенных аннотаций
public class AnnotationExample {

@Override
public String toString() {
return "AnnotationExample";
}

@Deprecated
public void oldMethod() {
System.out.println("This method is deprecated");
}

@SuppressWarnings("unchecked")
public void uncheckedOperation() {
List rawList = new ArrayList();
rawList.add("String");
}

@SafeVarargs
public final void safeVarargsMethod(List<String>... lists) {
for (List<String> list : lists) {
System.out.println(list);
}
}

@FunctionalInterface
interface MyFunctionalInterface {
void execute();
}
}


Методы аннотаций

Аннотации могут содержать методы. Методы аннотаций могут иметь значения по умолчанию.
@interface MyAnnotation {
String value();
int number() default 42;
}


Аннотацию можно использовать с параметрами:
@MyAnnotation(value = "Example", number = 10)
public class AnnotatedClass {
}


Аннотации и рефлексия

Аннотации можно считывать во время выполнения с помощью рефлексии. Это позволяет динамически изменять поведение программы в зависимости от аннотированных элементов.


Пример использования рефлексии для чтения аннотаций

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class ReflectionExample {

@MyAnnotation(value = "Test", number = 5)
public void annotatedMethod() {
}

public static void main(String[] args) throws Exception {
Method method = ReflectionExample.class.getMethod("annotatedMethod");

if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println("Value: " + annotation.value());
System.out.println("Number: " + annotation.number());
}
}
}


#Java #Training #Annotation #Medium