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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Использование интерфейсов для множественного наследования

// Создание интерфейсов
interface Printable {
void print();
}

interface Showable {
void show();
}

// Реализация интерфейсов в классе
class MyClass implements Printable, Showable {
public void print() {
System.out.println("Printing...");
}

public void show() {
System.out.println("Showing...");
}
}

public class Main {
public static void main(String[] args) {
// Создание объекта класса MyClass
MyClass obj = new MyClass();
obj.print();
obj.show();
}
}


🔎 В данном коде используются интерфейсы для реализации множественного наследования. Класс MyClass реализует два интерфейса Printable и Showable, и поэтому класс может использовать методы, определенные в обоих интерфейсах. Это позволяет создавать гибкие и модульные программы, используя механизм интерфейсов в Java.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥4👨‍💻21
⌨️ Использование StringBuilder для эффективной конкатенации строк:

public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append("строка ").append(i).append("\n");
}
String result = sb.toString();
System.out.println(result);
}
}


📌 В этом примере используется StringBuilder для объединения 10 строк "строка i" в одну строку. Это более эффективно, чем использование оператора "+" или String.concat(), особенно при большом количестве операций конкатенации строк.

StringBuilder предоставляет изменяемую последовательность символов и позволяет выполнять эффективные операции вставки, удаления и конкатенации строк.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥31
💻 Как полезную фишку на Java можно рассмотреть использование лямбда-выражений для упрощения написания анонимных классов. Например, использование лямбда-выражения для выполнения операции над элементами коллекции:

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

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

// Использование лямбда-выражения для вывода каждого элемента в консоль
numbers.forEach(n -> System.out.println(n));

// Использование лямбда-выражения для умножения каждого элемента на 2
numbers.replaceAll(n -> n * 2);
System.out.println(numbers); // Вывод: [2, 4, 6, 8, 10]
}
}


🔝 Использование лямбда-выражений делает код более компактным и удобочитаемым, особенно при работе с коллекциями и функциональными интерфейсами.
👍17🔥42🥰2
⌨️ Параллельное выполнение задач с использованием ExecutorService

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

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
public static void main(String[] args) {
// Создание пула потоков
ExecutorService executor = Executors.newFixedThreadPool(5);

// Подача задач на выполнение
for (int i = 0; i < 10; i++) {
executor.execute(new Task(i));
}

// Остановка пула потоков после выполнения задач
executor.shutdown();
}

static class Task implements Runnable {
private int taskId;

public Task(int taskId) {
this.taskId = taskId;
}

@Override
public void run() {
System.out.println("Выполнение задачи " + taskId + " в потоке " +
Thread.currentThread().getName());
}
}
}


🧑‍💻Этот код создает пул из 5 потоков и подает на выполнение 10 задач. Каждая задача выводит свой идентификатор и имя потока, в котором она выполняется. После выполнения всех задач пул потоков останавливается.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥53👨‍💻1
Did anyone say Java?
👍42🤣7🔥5😁3🤩2💯21
⌨️ Использование интерфейса Callable вместе с классом Future для выполнения асинхронных задач и получения их результата:

ExecutorService executor = null;
try {
executor = Executors.newFixedThreadPool(1);
Future<Integer> futureResult = executor.submit(() -> {
// Выполнение сложной вычислительной задачи
int result = 0;
for (int i = 0; i < 100; i++) {
result += i;
Thread.sleep(100);
}
return result;
});

// Другие действия, выполняемые параллельно

// Ожидание завершения асинхронной задачи и получение результата
Integer result = futureResult.get();
System.out.println("Результат: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
if (executor != null) executor.shutdown();
}

➡️В данном примере создается пул потоков размером 1, затем создается асинхронная задача с использованием интерфейса Callable, который возвращает результат типа Integer. Задача выполняет сложное вычисление с задержкой в 100 миллисекунд каждую итерацию.

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

Метод get() вызывается для ожидания завершения задачи и получения результата. Если задача еще не завершилась, вызов этого метода блокируется. Возможны исключения, такие как InterruptedException или ExecutionException, которые необходимо обработать.

💁‍♂️ Затем поток пул завершается вызовом shutdown().
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10👨‍💻32🔥1💯1
⌨️ Метод для глубокого копирования объектов. Это часто используется, когда нужно создать копию объекта, сохраняя его данные, но не связи с другими объектами.

📌 Вот пример метода для глубокого копирования:

import java.io.*;

public class DeepCopyExample {
public static void main(String[] args) {
Person person = new Person("John", 30);
Person deepCopy = deepCopy(person);

System.out.println("Original: " + person.getName() + ", " + person.getAge());
System.out.println("Deep copy: " + deepCopy.getName() + ", " + deepCopy.getAge());
}

public static <T extends Serializable> T deepCopy(T object) {
try {
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
objectOutputStream.writeObject(object);

ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteInputStream);
T copy = (T) objectInputStream.readObject();

return copy;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}

class Person implements Serializable {
private String name;
private int age;

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

public String getName() {
return name;
}

public int getAge() {
return age;
}
}


В этом примере мы создаем класс Person, который реализует интерфейс Serializable, чтобы объекты этого класса можно было сериализовать и десериализовать. Затем мы создаем метод deepCopy, который принимает объект и возвращает его глубокую копию.

Мы используем ByteArrayOutputStream и ObjectOutputStream, чтобы записать объект в байтовый массив, а затем ByteArrayInputStream и ObjectInputStream, чтобы прочитать копию объекта из массива.

В методе main мы создаем объект Person, затем создаем его глубокую копию с помощью метода deepCopy и выводим на экран значения оригинального и скопированного объекта.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍93🔥2👏1💯1👨‍💻1
⌨️ Использования анонимных классов:

Анонимный класс - это класс без имени, который объявляется и создается внутри другого класса или метода. Он удобен, когда требуется определить класс, который будет использоваться только один раз, и нет необходимости создавать отдельный класс.

public class Main {
interface Greeting {
void sayHello();
}

public static void main(String[] args) {
Greeting greeting = new Greeting() { // объявление и создание анонимного класса
@Override
public void sayHello() {
System.out.println("Привет, мир!");
}
};

greeting.sayHello(); // вызов метода sayHello у анонимного класса
}
}


В данном примере мы определили интерфейс Greeting, содержащий метод sayHello(). Затем, в методе main(), мы создали анонимный класс, реализующий интерфейс Greeting и переопределивший метод sayHello(). Затем мы вызываем метод sayHello() у объекта анонимного класса.

📝Таким образом, анонимные классы предоставляют удобный способ создания и использования классов "на лету", что может быть полезно, когда требуется определить классы, которые будут использоваться только в одном месте программы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84🔥3👏1
⌨️ Работа с коллекциями элементарных типов данных благодаря классам-оболочкам (Wrapper Classes)


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

public class WrapperExample {
public static void main(String[] args) {
// Создание списка оберток для целых чисел
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);

// Использование методов класса-оболочки
int sum = 0;
for (int i = 0; i < numbers.size(); i++) {
sum += numbers.get(i);
}
System.out.println("Сумма чисел: " + sum);
}
}


В этом примере создается список оберток numbers для целых чисел типа Integer. Затем мы добавляем в список несколько элементов и используем метод get() для получения элементов из списка. Значения оберток автоматически анбоксируются в примитивные типы данных int, и мы можем выполнять с ними операции, например, суммирование.
Использование классов-оболочек позволяет работать с коллекциями элементарных типов данных и обеспечивает удобство и безопасность при работе с ними.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥112👍2👏1
⌨️ Обработка исключений с помощью Try-With-Resources.

Try-With-Resources - это новая конструкция языка, введенная в Java 7, которая облегчает работу с ресурсами такими как файлы или сокеты и сокращает количество кода, необходимого для обработки исключений.

Вот пример использования Try-With-Resources для чтения содержимого файла:

try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}


💻В этом примере мы открываем BufferedReader внутри блока try с помощью конструктора FileReader. Затем мы можем безопасно читать файл внутри этого блока без необходимости явно закрывать ресурс.

После завершения блока try автоматически вызывается метод close() объекта reader, который закрывает файл и освобождает связанные с ним ресурсы. Если возникнет исключение в блоке try, его можно будет обработать в блоке catch после завершения работы с ресурсом.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3👏2🥰1
🤣35😁6🤯4💯3👍1
⌨️ Использование CompletableFuture для асинхронных операций.

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

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureExample {
public static void main(String[] args) {
// Создание CompletableFuture объекта
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

// Добавление операций после выполнения асинхронной задачи
CompletableFuture<String> result = future.thenApplyAsync(str -> str + " World")
.thenApply(str -> str + "!");

try {
// Ожидание результата
String message = result.get();
System.out.println(message);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}


🧑‍💻В данном примере мы создаем CompletableFuture объект future, который возвращает строку "Hello". Затем мы добавляем операции thenApplyAsync и thenApply, которые обрабатывают результат асинхронной задачи и добавляют к нему слова "World" и "!", соответственно.

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

💁‍♂️ Таким образом, использование CompletableFuture позволяет нам эффективно работать с асинхронными задачами и упрощает обработку результатов. Это может быть особенно полезно в многопоточном или параллельном программировании.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9👨‍💻31
⌨️ Использование Stream API для работы с коллекциями данных.

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

public class StreamExample {
public static void main(String[] args) {
List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");

// Фильтрация элементов, начинающихся с буквы "a" и преобразование в верхний регистр
fruits.stream()
.filter(fruit -> fruit.startsWith("a"))
.map(String::toUpperCase)
.forEach(System.out::println);
// Выведет "APPLE"
}
}


📝 В этом примере мы использовали Stream API для фильтрации элементов коллекции, начинающихся с буквы "a", и преобразования их в верхний регистр, а затем вывели результат в консоль. Stream API предоставляет мощный и удобный способ работы с коллекциями данных в Java, позволяя выполнять различные операции, такие как фильтрация, отображение, сортировка, агрегация и многое другое.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥4👏21
⌨️ Код для реализации уникального идентификатора (UUID):

import java.util.UUID;

public class UniqueIdGenerator {

public static void main(String[] args) {
// Генерация случайного уникального идентификатора
UUID uuid = UUID.randomUUID();
System.out.println("Уникальный идентификатор: " + uuid);

// Преобразование уникального идентификатора в строку без тире
String uuidString = uuid.toString().replace("-", "");
System.out.println("Уникальный идентификатор без тире: " + uuidString);
}


Этот код генерирует случайный уникальный идентификатор (UUID) и выводит его значение в формате с и без использования тире. Уникальный идентификатор предоставляет уникальное значение, которое может быть использовано для идентификации объектов, сессий, операций и т. д.

Это полезно, например, при создании уникального идентификатора для записи в базу данных или для генерации уникального имени файла.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍111🥰1👏1
⌨️ Использование класса java.time.Duration для рассчета разницы во времени между двумя моментами.

Код для расчета разницы во времени:




import java.time.Duration;
import java.time.LocalDateTime;

public class TimeDifferenceCalculator {
public static void main(String[] args) {
LocalDateTime startTime = LocalDateTime.of(2022, 1, 1, 10, 0, 0);
LocalDateTime endTime = LocalDateTime.of(2022, 1, 1, 12, 30, 0);

Duration duration = Duration.between(startTime, endTime);

long hours = duration.toHours();
long minutes = duration.toMinutes() % 60;
long seconds = duration.getSeconds() % 60;

System.out.println("Time difference: " + hours + " hours, " + minutes + " minutes, " + seconds + " seconds.");
}
}


В этом примере мы создаем два объекта LocalDateTime - startTime и endTime, представляющие начальное и конечное время соответственно. Затем мы используем метод Duration.between() для расчета разницы во времени между startTime и endTime.

Далее, мы используем методы toHours(), toMinutes() и getSeconds() для получения часов, минут и секунд в полученной разнице времени. Наконец, мы выводим результаты на экран.

Эта фишка полезна для рассчета временных интервалов, например, для измерения времени выполнения определенной операции или анализа времени работы программы.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤝6👍51🔥1🏆1
⌨️ Использование класса java.util.Timer для выполнения задач по расписанию.

Для этого необходимо импортировать соответствующие пакеты:

import java.util.Timer;
import java.util.TimerTask;


Затем можно создать класс, который наследует TimerTask и реализует метод run() для определения задачи:

class ScheduledTask extends TimerTask {
public void run() {
// выполняем задачу
System.out.println("Задача выполняется!");
}
}


Далее, в основном методе программы, можно создать экземпляр класса Timer и использовать его для запуска задачи с определенной периодичностью:

public class Main {
public static void main(String[] args) {
Timer timer = new Timer();

// создаем экземпляр задачи
ScheduledTask task = new ScheduledTask();

// задержка перед выполнением задачи (в миллисекундах)
long delay = 1000;

// интервал между выполнениями задачи (в миллисекундах)
long period = 2000;

// запускаем задачу по расписанию
timer.schedule(task, delay, period);
}
}


В данном примере задача будет выполняться сначала через 1 секунду после запуска программы, а затем повторяться каждые 2 секунды. В приведенном коде основной поток программы просто ждет выполнения задачи и не блокируется.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍71🤡1
😁18🤣4🔥21🤩1🤪1
⌨️ Использование модификатора volatile для переменных, которые используются множеством потоков.

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

Вот пример кода:

public class VolatileExample {
private volatile boolean flag = false;

public void setFlag(boolean value) {
flag = value;
}

public boolean getFlag() {
return flag;
}
}


Когда переменная flag объявлена с модификатором volatile, можно гарантировать, что любые изменения значения flag будут немедленно видны всем потокам, которые обращаются к методу getFlag(). Таким образом, нет необходимости использовать синхронизацию для чтения и записи значения flag в разных потоках.

Использование модификатора volatile может помочь предотвратить ошибки синхронизации и упростить код в многопоточных приложениях. Однако необходимо быть осторожным при использовании этого модификатора, так как он не гарантирует атомарность операций и не является заменой для других механизмов синхронизации, таких как блокировки или атомарные классы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥21👏1
⌨️ Использование аннотации @FunctionalInterface для определения функциональных интерфейсов.

Функциональные интерфейсы - это интерфейсы, которые содержат только один абстрактный метод и могут использоваться как типы данных для лямбда-выражений или методов высшего порядка.

При использовании аннотации @FunctionalInterface вы указываете компилятору, что этот интерфейс должен содержать только один абстрактный метод, чтобы избежать возможных ошибок при использовании лямбда-выражений или ссылок на методы.

Ниже приведен пример кода, демонстрирующий использование аннотации @FunctionalInterface:

@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}

public class FunctionalInterfaceExample {
public static void main(String[] args) {
Calculator addition = (a, b) -> a + b;
System.out.println("Результат сложения: " + addition.calculate(5, 3));

Calculator subtraction = (a, b) -> a - b;
System.out.println("Результат вычитания: " + subtraction.calculate(5, 3));
}
}


В этом примере мы создаем функциональный интерфейс Calculator, содержащий метод calculate. Затем мы создаем экземпляры интерфейса, используя лямбда-выражения, и вызываем метод calculate для выполнения операций сложения и вычитания.

Применение аннотации @FunctionalInterface помогает нам убедиться, что в интерфейсе действительно определен только один абстрактный метод, и предотвращает случайные ошибки при использовании функциональных интерфейсов в нашем коде.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍101🔥1👏1
⌨️ Использование логгирования с помощью фреймворка SLF4J в сочетании с Logback в качестве реализации.

SLF4J (Simple Logging Facade for Java) обеспечивает интерфейс для логгирования, который является общим для различных реализаций логгеров (например, Logback или Log4j). Это позволяет вам изменить реализацию логгера без изменения кода.

1️⃣ Для начала установите зависимости в вашем файле pom.xml:

<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.0-alpha5</version>
</dependency>
</dependencies>

2️⃣ Затем создайте класс с помощью следующего кода, чтобы протестировать логгирование:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ExampleLogger {
private static final Logger logger = LoggerFactory.getLogger(ExampleLogger.class);

public static void main(String[] args) {
logger.debug("This is a debug message");
logger.info("This is an info message");
logger.warn("This is a warning message");
logger.error("This is an error message");
}
}


В этом примере мы создаем статическое поле logger с помощью LoggerFactory и инициализируем его с классом, в котором он используется (ExampleLogger). Затем мы можем использовать этот logger, чтобы записывать различные уровни сообщений (debug, info, warn, error).

3️⃣ Чтобы настроить вывод логов, создайте файл logback.xml в ресурсах вашего проекта со следующим содержимым:

<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>


Эта конфигурация использует ConsoleAppender для вывода логов на консоль. Он также определяет формат вывода логов с использованием pattern. Уровень логов задан как INFO, что означает, что будут выводиться все сообщения уровней INFO, WARN и ERROR.

Теперь при запуске класса ExampleLogger вы увидите сообщения различных уровней вывода в соответствии с вашей конфигурацией логгера.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍141