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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Обработка исключений с помощью 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
⌨️ Использование методов проверки исключений для улучшения обработки исключений в коде.

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

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

public class ExampleException extends Exception {
public ExampleException(String message) {
super(message);
}
}

public class ExampleClass {
public void doSomething(int value) throws ExampleException {
if (value < 0) {
throw new ExampleException("Value can't be negative");
}
// выполнение кода
}
}

public class Main {
public static void main(String[] args) {
ExampleClass example = new ExampleClass();
try {
example.doSomething(-1);
} catch (ExampleException e) {
System.out.println(e.getMessage());
}
}
}


В данном примере у нас есть класс ExampleException, который расширяет класс Exception и используется для определения собственного исключения. В классе ExampleClass мы определяем метод doSomething, который проверяет значение параметра value и выбрасывает исключение ExampleException, если значение отрицательное. В классе Main мы создаем объект ExampleClass и вызываем метод doSomething с отрицательным значением, а затем обрабатываем выброшенное исключение.

Использование методов проверки исключений позволяет нам явно указывать, какие исключения могут возникнуть в методе, и позволяет более точно управлять обработкой исключений в коде. Это становится особенно полезным в больших проектах, где нужно более точно контролировать и обрабатывать исключения.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥3👏1
⌨️ Использование аннотаций (Annotations) для улучшения читаемости и обработки кода:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}


Данная аннотация @LogExecutionTime позволяет отмечать методы в Java классах, чтобы измерять время выполнения этих методов. Для использования аннотации, следует применить ее к методу, который необходимо измерить:

public class ExampleClass {

@LogExecutionTime
public void performTimeConsumingTask() {
// Выполняем длительную задачу для измерения времени
}
}


Теперь, можно создать аспект (Aspect) с использованием библиотеки AspectJ или Spring AOP для обработки методов, помеченных аннотацией @LogExecutionTime, и измерить время их выполнения:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
public class LogExecutionTimeAspect {

@Pointcut("@annotation(LogExecutionTime)")
public void logExecutionTime() {
}

@Around("logExecutionTime()")
public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - startTime;
System.out.println(joinPoint.getSignature() + " выполнен за " + executionTime + "ms");
return proceed;
}
}


Aspect LogExecutionTimeAspect создает возможность измерить время выполнения методов, помеченных аннотацией @LogExecutionTime, путем перехвата вызова метода и расчета времени выполнения. Это может быть очень полезным для оптимизации производительности и анализа кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍82🔥2
😁31🤪5🤣4🔥2🤯2😢1
⌨️ Использование методов default и static в интерфейсах. Эти методы позволяют добавлять конкретные реализации в интерфейсы, что делает их более гибкими и позволяет избежать некоторых проблем множественного наследования.

Пример с default методом в интерфейсе:

interface Greeter {
void greet();

// Default метод в интерфейсе
default void greetWithExclamation() {
System.out.println("Привет, мир!");
}
}

class EnglishGreeter implements Greeter {
public void greet() {
System.out.println("Hello, World!");
}
}

class RussianGreeter implements Greeter {
public void greet() {
System.out.println("Привет, мир!");
}

// Переопределение default метода
@Override
public void greetWithExclamation() {
System.out.println("Привет, мир!!!");
}
}

public class InterfaceDefaultMethodExample {
public static void main(String[] args) {
Greeter englishGreeter = new EnglishGreeter();
englishGreeter.greet(); // Вызовет: Hello, World!
englishGreeter.greetWithExclamation(); // Вызовет: Привет, мир!

Greeter russianGreeter = new RussianGreeter();
russianGreeter.greet(); // Вызовет: Привет, мир!
russianGreeter.greetWithExclamation(); // Вызовет: Привет, мир!!!
}
}


Пример со static методом в интерфейсе:

interface Calculator {
static int add(int a, int b) {
return a + b;
}

static int subtract(int a, int b) {
return a - b;
}
}

public class InterfaceStaticMethodExample {
public static void main(String[] args) {
// Нет необходимости создавать экземпляр интерфейса
int sum = Calculator.add(5, 3); // 8
int difference = Calculator.subtract(5, 3); // 2
System.out.println("Сумма: " + sum + ", Разница: " + difference);
}
}


В этих примерах методы default и static в интерфейсе предоставляют замечательные возможности для разработки. Методы default позволяют добавить новые функции в интерфейсы без нарушения контракта с существующими реализациями. static методы в интерфейсах позволяют определять вспомогательные методы, которые могут быть вызваны без объекта интерфейса, предоставляя большую гибкость и удобство в использовании.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥1🤓1👨‍💻1
⌨️ Использование java.util.stream.Collectors для обработки коллекций

Код:

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

public class StreamCollectorsExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Примеры использования Collectors
// Преобразование элементов коллекции в строку
String numbersAsString = numbers.stream()
.map(Object::toString)
.collect(Collectors.joining(", "));
System.out.println("Числа в виде строки: " + numbersAsString);

// Получение среднего значения всех элементов коллекции
double average = numbers.stream()
.collect(Collectors.averagingInt(Integer::intValue));
System.out.println("Среднее значение: " + average);

// Фильтрация элементов и сборка их в новую коллекцию
List<Integer> evenNumbers = numbers.stream()
.filter(num -> num % 2 == 0)
.collect(Collectors.toList());
System.out.println("Четные числа: " + evenNumbers);

// Группировка элементов по условию
System.out.println("Числа по остатку от деления на 3: " + numbers.stream()
.collect(Collectors.groupingBy(num -> num % 3)));
}
}


⚙️Этот пример демонстрирует использование класса Collectors из пакета java.util.stream для более эффективной обработки коллекций в Java. Методы класса Collectors предоставляют различные операции для сбора (collecting) элементов из потока данных в различные структуры данных или для выполнения агрегатных операций над элементами потока.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍171🔥1👏1
⌨️ Использование аннотации @Override.

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

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

class Animal {
public void makeSound() {
System.out.println("Some sound");
}
}

class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Bark");
}
}

public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound();
}
}


В приведенном примере метод makeSound() в классе Dog переопределяет метод с таким же именем из класса Animal. При использовании аннотации @Override компилятор проверяет, действительно ли метод переопределяет метод суперкласса, что помогает избежать ошибок, например, опечаток в названии метода. Если метод в подклассе не переопределяет метод суперкласса, компилятор выдаст ошибку.

📈Использование аннотации @Override повышает качество кода, делает его более читаемым и помогает избегать ошибок при работе с наследованием методов. Рекомендуется использовать эту аннотацию при переопределении методов в Java.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41🔥1👏1👨‍💻1
⌨️ "Фабричный метод" (Factory Method).

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

Пример реализации:

1️⃣Создадим интерфейс продукта, который будет производиться фабричным методом.

interface Product {
void use();
}


2️⃣Создадим реализации продуктов.

class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("Using ConcreteProductA");
}
}

class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("Using ConcreteProductB");
}
}


3️⃣Создадим абстрактный класс с фабричным методом.

abstract class Creator {
public abstract Product factoryMethod();

public void anOperation() {
Product product = factoryMethod();
product.use();
}
}


4️⃣Реализуем конкретные создатели для каждого типа продукта.

class ConcreteCreatorA extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}

class ConcreteCreatorB extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}


5️⃣Демонстрация использования.

public class FactoryMethodDemo {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
creatorA.anOperation(); // Использует ConcreteProductA

Creator creatorB = new ConcreteCreatorB();
creatorB.anOperation(); // Использует ConcreteProductB
}
}


В этом примере FactoryMethodDemo класс демонстрирует использование фабричного метода. Creator класс содержит фабричный метод factoryMethod(), который переопределяется в подклассах ConcreteCreatorA и ConcreteCreatorB для создания конкретных продуктов ConcreteProductA и ConcreteProductB соответственно.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92🔥2👎1🥰1💊1
😁28🤣18👍4🤪1
⌨️ Использование аннотаций @Deprecated для метаданных и управления поведением программы.

Пример кода:

@Deprecated
public class OldFeature {
// Код устаревшей функциональности
}


✔️В данном примере аннотация @Deprecated помечает класс как устаревший, что уведомляет других разработчиков о том, что следует избегать использования этой функциональности в своем коде. Использование аннотаций позволяет добавлять метаданные и контролировать поведение программы, что делает код более понятным и управляемым.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍82🔥2