@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
👍10❤1🔥1👏1
SLF4J (Simple Logging Facade for Java) обеспечивает интерфейс для логгирования, который является общим для различных реализаций логгеров (например, Logback или Log4j). Это позволяет вам изменить реализацию логгера без изменения кода.<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>
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).<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
👍14❤1
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
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
👍8❤2🔥2
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
👍17❤1🔥1👏1
Эта аннотация используется для явного указания того, что метод в подклассе переопределяет метод из суперкласса, что помогает избежать ошибок при написании кода.
Пример использования аннотации @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 компилятор проверяет, действительно ли метод переопределяет метод суперкласса, что помогает избежать ошибок, например, опечаток в названии метода. Если метод в подклассе не переопределяет метод суперкласса, компилятор выдаст ошибку.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1🔥1👏1👨💻1
Factory Method).Этот паттерн позволяет создавать объекты без указания конкретных классов объектов. Вместо прямого создания объекта класса, создание объекта делегируется методу (фабричному методу), который может быть переопределен подклассом, чтобы изменить тип создаваемого объекта.
Пример реализации:
interface Product {
void use();
}
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");
}
}
abstract class Creator {
public abstract Product factoryMethod();
public void anOperation() {
Product product = factoryMethod();
product.use();
}
}
class ConcreteCreatorA extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}
class ConcreteCreatorB extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}
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
👍9❤2🔥2👎1🥰1💊1
Пример кода:
@Deprecated
public class OldFeature {
// Код устаревшей функциональности
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2🔥2
Java | Фишки и трюки
Чистый код: создание, анализ и рефакторинг Автор: Роберт Мартин Эту книгу должен прочитать каждый разработчик. А затем перечитывать каждый год! 😁 Плюс для джавистов в том что в книге все примеры написаны на Java. "Чистый код" Роберта Мартина – это практическое…
📚 Чистый код. Наименования и разделения
✅ Используй понятные и удобнопроизносимые имена для любых сущностей. Они должны описывать почему эта сущность существует, что она делает и как используется.
✅ Не бойся тратить время на выбор лучшего и понятного имени. Ты выиграешь в будущем при работе или чтении этого кода.
✅ Если название сущности не соответствует еë функционалу или по названию не понятно, что сущность делает, то еë надо переименовать в самое понятное название. Если этого сделать невозможно, то значит с еë функционалом что-то не так и еë надо рефакторить.
✅ Сущность, которая имеет в названии "And", "With" — нарушает Single Responsibility. Функционал такой сущности стоит разделять. Но этим правилом стоит иногда пренебрегать.
✅ Непонятные тексты, строки стоит выносить в переменные и давать им понятные названия.
✅ Названия методов должны содержать глагол, который описывает, что этот метод делает и ключевое слово с которым работает данный метод. Если в названии метода нет глагола, то эта сущность не должна быть методом или ему нужно дать правильное название.
✅ Нужно избегать одинаковых наименований для двух разных целей.
✅ Если сущность имеет схожее с другой сущностью название, то скорее всего их функционал очень сильно похож и их нужно объединить? Если нет, то их названия нужно менять так, чтобы они не были похожими.
✅ Если ты мысленно переименовываешь сущность, когда читаешь код, чтобы тебе было понятнее понимать её функционал, то переименуй её в это мысленное название.
✅ Выбери одно слово для одной концепции. Сложно будет понимать функционал, когда у тебя есть fetch, retrieve и get в названиях. Пусть лучше везде будет get.
✅ Длинное и понятное имя лучше, чем короткое, но непонятное.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥3❤1
Пример кода:
$ 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!"
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥3❤1
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 можно профилировать работу приложения в реальном времени, собирать данные о производительности и возможных узких местах.
Он позволяет записывать и в последствии анализировать огромное количество метрик и событий, происходящих внутри JVM, что значительно облегчает анализ проблем.
Более того, при определённых настройках его накладные расходы настолько малы, что многие (включая Oracle) рекомендуют держать его постоянно включённым везде, в том числе в прод, чтобы в случае возникновения проблем сразу иметь полную картину происходившего с приложением.
JFR это мощный инструмент для оптимизации производительности Java-приложений.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2🔥1🥰1
Этот метод предлагает удобный способ вычисления и вставки значений в карту, если они отсутствуют.
Пример кода с объяснением:
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));
}
}
Этот метод предоставляет удобный и эффективный способ добавления значений в карту, если они отсутствуют, что может помочь упростить код и избежать лишних проверок на наличие ключей в карте.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤1🔥1👏1
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();
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2👏1
Начиная с 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
👍4❤2
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(); // Уменьшение счетчика
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍1