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

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

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Использование аннотации @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
Java | Фишки и трюки
Чистый код: создание, анализ и рефакторинг Автор: Роберт Мартин Эту книгу должен прочитать каждый разработчик. А затем перечитывать каждый год! 😁 Плюс для джавистов в том что в книге все примеры написаны на Java. "Чистый код" Роберта Мартина – это практическое…
📚 Чистый код. Наименования и разделения

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

Не бойся тратить время на выбор лучшего и понятного имени. Ты выиграешь в будущем при работе или чтении этого кода.

Если название сущности не соответствует еë функционалу или по названию не понятно, что сущность делает, то еë надо переименовать в самое понятное название. Если этого сделать невозможно, то значит с еë функционалом что-то не так и еë надо рефакторить.

Сущность, которая имеет в названии "And", "With" — нарушает Single Responsibility. Функционал такой сущности стоит разделять. Но этим правилом стоит иногда пренебрегать.

Непонятные тексты, строки стоит выносить в переменные и давать им понятные названия.

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

Нужно избегать одинаковых наименований для двух разных целей.

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

Если ты мысленно переименовываешь сущность, когда читаешь код, чтобы тебе было понятнее понимать её функционал, то переименуй её в это мысленное название.

Выбери одно слово для одной концепции. Сложно будет понимать функционал, когда у тебя есть fetch, retrieve и get в названиях. Пусть лучше везде будет get.

Длинное и понятное имя лучше, чем короткое, но непонятное.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥31
🔔Использование JShell для быстрой проверки и экспериментов с кодом.

Пример кода:

$ jshell
| Welcome to JShell -- Version 11.0.12
| For an introduction type: /help intro

jshell> int result = 10 + 20;
result ==> 30

jshell> String message = "Hello, World!";
message ==> "Hello, World!"


✔️JShell позволяет быстро проводить эксперименты, проверять короткие фрагменты кода, тестировать API и проводить быстрые исследования. Он предоставляет удобную среду для интерактивной работы с Java кодом без необходимости создания и компиляции отдельных файлов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥31
⌨️ Десериализация сложных типов с помощью Gson


String json = """
{
"Orwell1": "War is Peace.",
"Orwell2": "Freedom is Slavery.",
"Orwell3": "Ignorance is Strength."
}
""";

Type mapType = new TypeToken<Map<String, String>>() { }.getType();
Map<String, String> map = new Gson().fromJson(json, mapType);


Gson или Google Gson — это библиотека Java с открытым исходным кодом, которая сериализует объекты Java в JSON (и десериализует их обратно в Java).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥1👨‍💻1
⌨️ Использование Java Flight Recorder (JFR) для профилирования приложений в реальном времени.

С помощью Java Flight Recorder можно профилировать работу приложения в реальном времени, собирать данные о производительности и возможных узких местах.

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

Более того, при определённых настройках его накладные расходы настолько малы, что многие (включая Oracle) рекомендуют держать его постоянно включённым везде, в том числе в прод, чтобы в случае возникновения проблем сразу иметь полную картину происходившего с приложением.

JFR это мощный инструмент для оптимизации производительности Java-приложений.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍122🔥1🥰1
☕️Использование метода computeIfAbsent() из интерфейса Map.

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

Пример кода с объяснением:

import java.util.HashMap;
import java.util.Map;

public class MapExample {
public static void main(String[] args) {
Map<String, Integer> wordLengths = new HashMap<>();
String word = "apple";

// Использование computeIfAbsent для вычисления и вставки значения в карту
wordLengths.computeIfAbsent(word, String::length);

// Вывод длины слова "apple", которая была вычислена и вставлена в карту
System.out.println("Длина слова apple: " + wordLengths.get(word));
}
}
🔒В этом примере мы используем метод computeIfAbsent() для карты wordLengths, чтобы вычислить и вставить длину слова "apple" в карту, если она отсутствует. Если значение уже присутствует, метод возвращает текущее значение.

Этот метод предоставляет удобный и эффективный способ добавления значений в карту, если они отсутствуют, что может помочь упростить код и избежать лишних проверок на наличие ключей в карте.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍131🔥1👏1
😁34🤣4👍3🔥2👏1
☕️Использование ScheduledExecutorService

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class MultithreadingExample {

public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

// Запланировать выполнение задачи через определенное время
ScheduledFuture<?> future = executor.schedule(() -> {
// Выполнить задачу
System.out.println("Выполняется отложенная задача");
}, 3, TimeUnit.SECONDS);

// Планирование регулярного выполнения задачи с определенной задержкой
executor.scheduleAtFixedRate(() -> {
// Выполнить регулярную задачу
System.out.println("Выполняется регулярная задача");
}, 0, 1, TimeUnit.SECONDS);

// Завершение работы с пулом потоков
executor.shutdown();
}
}
⚙️В данном примере мы используем ScheduledExecutorService для планирования отложенного выполнения задачи и регулярного выполнения задачи с определенной задержкой. ScheduledExecutorService позволяет управлять выполнением задач в установленное время и в регулярном режиме с учетом временных интервалов.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2👏1
☕️Использования коллекций неизменяемых (immutable) элементов.

Начиная с Java 9, была добавлена возможность использования коллекций неизменяемых (immutable) элементов. Это достигается с помощью метода of в классе List, Set и Map. Вот пример:

// Создание неизменяемого списка
List<String> immutableList = List.of("apple", "banana", "cherry");

// Создание неизменяемого множества
Set<String> immutableSet = Set.of("apple", "banana", "cherry");

// Создание неизменяемой карты
Map<String, Integer> immutableMap = Map.of("apple", 1, "banana", 2, "cherry", 3);
✔️Это полезно, поскольку неизменяемые коллекции обеспечивают безопасность параллельного доступа и гарантируют, что данные остаются неизменными. Это особенно полезно в многопоточных средах и предотвращает неожиданные изменения данных. Также это может улучшить читаемость кода, подчеркивая намерение сделать коллекцию неизменяемой.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42
☕️Использование CountDownLatch

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

Пример кода:

import java.util.concurrent.CountDownLatch;

public class Main {
public static void main(String[] args) throws InterruptedException {
int count = 3;
CountDownLatch latch = new CountDownLatch(count);

// Потоки, которые будут уменьшать счетчик
new Thread(new Worker(latch)).start();
new Thread(new Worker(latch)).start();
new Thread(new Worker(latch)).start();

// Ожидание завершения всех потоков
latch.await();
System.out.println("Все потоки завершили работу");
}
}

class Worker implements Runnable {
private CountDownLatch latch;

Worker(CountDownLatch latch) {
this.latch = latch;
}

public void run() {
// Имитация выполнения работы
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Поток завершил работу");
latch.countDown(); // Уменьшение счетчика
}
}
📣В этом примере создается объект CountDownLatch с начальным значением 3, и три потока уменьшают его значение перед завершением своей работы. Главный поток ожидает, пока значение счетчика не достигнет 0, после чего выводится сообщение о завершении всех потоков.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍1
☕️Использование аспектно-ориентированного программирования с помощью фреймворка AspectJ

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

Пример кода:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.JoinPoint;

@Aspect
public class LoggingAspect {

@Before("execution(* com.example.service.*.*(..))")
public void beforeServiceMethod(JoinPoint joinPoint) {
System.out.println("Логирование: Вызов метода " + joinPoint.getSignature().getName());
}
}
🔈В этом примере мы создаем аспект LoggingAspect, который использует фреймворк AspectJ для перехвата вызовов методов в пакете com.example.service. С помощью аспектно-ориентированного программирования мы можем внедрять логику логирования или другие операции в код без изменения самого кода, улучшая его модульность и поддерживаемость.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥21👨‍💻1
☕️Использование трассировки стека:

Отлов багов – это, возможно, самая трудоемкая составляющая процесса разработки на Java. Трассировка стека позволяет отследить, в каком именно месте проекта было выброшено исключение.

public class StackTraceExample {

public static void main(String[] args) {
try {
method1();
} catch (Exception e) {
e.printStackTrace(); // Вывод трассировки стека
}
}

public static void method1() {
method2();
}

public static void method2() {
method3();
}

public static void method3() {
throw new RuntimeException("Custom exception message");
}
}
🔈В этом примере показано как генерировать и обрабатывать трассировку стека в Java. Когда метод method3 вызывает исключение, это исключение перехватывается в методе main, и затем с помощью вызова e.printStackTrace() выводится трассировка стека, которая содержит информацию о вызове каждого метода от точки, где произошло исключение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42👏2
☕️Использование Java Reflection API для динамической инспекции и манипуляции с классами, методами, полями и другими элементами программы во время выполнения.

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

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

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class MyClass {
private String name;

public MyClass(String name) {
this.name = name;
}

public void printInfo() {
System.out.println("Name: " + name);
}
}

public class Main {
public static void main(String[] args) throws Exception {
MyClass obj = new MyClass("John");

// Получение класса
Class<?> clazz = obj.getClass();

// Получение и установка значения поля
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
System.out.println("Original value: " + field.get(obj));
field.set(obj, "Alice");
System.out.println("Updated value: " + field.get(obj));

// Вызов метода
Method method = clazz.getDeclaredMethod("printInfo");
method.invoke(obj);
}
}


🔔В этом примере используется Java Reflection API для получения доступа к полю name, изменения его значения, вызова метода printInfo и вывода информации об объекте класса MyClass. Reflection API предоставляет возможность обращаться к классам и их элементам динамически во время выполнения программы, что делает его мощным инструментом для реализации различных функций в профессиональной разработке на Java.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥1
☕️Использование аннотаций @SuppressWarnings

Аннотация @SuppressWarnings в Java используется для подавления предупреждений компилятора или IDE. Это может быть полезно, если вы уверены, что определенное предупреждение не является критическим и хотите, чтобы компилятор пропустил его. Однако следует использовать эту аннотацию осторожно, поскольку она может скрыть проблемы в коде.

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

public class DeprecatedExample {

@SuppressWarnings("deprecation")
public void useDeprecatedMethod() {
// Используем устаревший метод
DeprecatedClass deprecatedClass = new DeprecatedClass();
deprecatedClass.deprecatedMethod();
}

public static void main(String[] args) {
DeprecatedExample example = new DeprecatedExample();
example.useDeprecatedMethod();
}
}
✔️В данном примере метод useDeprecatedMethod() использует метод deprecatedMethod() из класса DeprecatedClass, который помечен аннотацией @Deprecated как устаревший. Аннотация @SuppressWarnings("deprecation") подавляет предупреждение компилятора о том, что используется устаревший метод, и позволяет успешно скомпилировать код без предупреждений.

Помните, что использование аннотации @SuppressWarnings должно быть обосновано, и важно следить за качеством кода, чтобы не упустить потенциальные проблемы в вашем приложении.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🎉1🤩1🍾1
😁27🤣9😱2👏1
☕️Использование библиотеки Lombok для автоматической генерации геттеров, сеттеров и конструкторов в Java.

Пример кода:

import lombok.Getter;
import lombok.Setter;

public class User {

@Getter @Setter
private String name;

@Getter @Setter
private int age;

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

⚙️С помощью аннотаций @Getter и @Setter от Lombok, не нужно писать многочисленные геттеры и сеттеры для каждого поля класса. Библиотека автоматически их сгенерирует во время компиляции. Это значительно упрощает процесс программирования и делает код более чистым и понятным.
Please open Telegram to view this post
VIEW IN TELEGRAM
14👍3👏1
☕️Пример Java кода для реализации алгоритма быстрой сортировки


public class QuickSort {
// Метод для обмена элементов
private static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}

// Основной метод быстрой сортировки
public static void quickSort(int[] array, int low, int high) {
if (array == null || array.length == 0){
return;
}
if (low >= high){
return;
}

// Выбор опорного элемента (pivot)
int middle = low + (high - low) / 2;
int pivot = array[middle];

// Разделение на подмассивы
int i = low, j = high;
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
swap(array, i, j);
i++;
j--;
}
}

// Рекурсивные вызовы для подмассивов
if (low < j){
quickSort(array, low, j);
}
if (high > i){
quickSort(array, i, high);
}
}

// Тестирование алгоритма
public static void main(String[] args) {
int[] array = {9, -3, 5, 2, 6, 8, -6, 1, 3};
System.out.println("Исходный массив: " + Arrays.toString(array));
quickSort(array, 0, array.length - 1);
System.out.println("Отсортированный массив: " + Arrays.toString(array));
}
}


🔈 Реализация алгоритма включает в себя метод quickSort, осуществляющий сортировку массива чисел, включающий в себя выбор опорного элемента, разделение на подмассивы и рекурсивные вызовы. Также, есть метод swap для обмена элементов и метод main для тестирования алгоритма.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52🔥1👏1😁1