Когда в Java использовать Record вместо Class и наоборот
Источник: Medium Изучив это руководство, вы научитесь точно определять, в каких ситуациях стоит использовать Record вместо Class и наоборот. Недавно я получил комментарий, в котором предлагалось преобразовать определенный Class в Record. Я задумался, в каких же случаях нам следует использовать Record вместо Class, а когда Class вместо Record. Сегодня мне хотелось бы изложить по этому поводу свои наблюдения.Что такое Record в Java?
Я предполагаю, что вы уже осведомлены о записи (Record) в Java, но в любом случае я кратко напомню о ней. Records впервые представлены в Java 14 в качестве предварительной версии, а затем они стали стандартной функцией в Java 16.
// Как определить record
public record Person(String name, int age) { }
// Как использовать record.
Person person = new Person("Tommy", 21);
// методы получения record.
System.out.println(person.name(), person.age());
Исходя из названия, Record предназначена для хранения неизменяемой записи (то есть, определенной информации). Например, я хочу сохранить имя человека и его дату рождения или страну и ее столицу. Это неизменяемая информация. Раньше я бы создал POJO (обычный старый объект Java) или Hashmap. Очевидно, это были не самые чистые решения. Теперь я могу просто создать запись (Record):
public record ApiResponse (int statusCode, String message) {}
Record имеет встроенные функции toString(), equals() и hashCode().
Person tommy = new Person("Tommy", 12);
Person bomma = new Person("Bomma", 18);
Person bomma2 = new Person("Bomma", 18);
// встроенная toString()
System.out.println(tommy);
// будет напечатано: Person[name=Tommy, age=12]
// встроенная функция equals() для проверки равенства двух записей
System.out.println(tommy.equals(bomma));// false
System.out.println(bomma2.equals(bomma));// true
Я не буду вдаваться в преимущества Record над Class или наоборот, потому что у обоих есть свои варианты использования. Нужно лишь понять, когда их применять в зависимости от ситуации.
Когда мы должны использовать Record вместо Class
Итак, давайте поговорим об основной цели этой статьи. Когда использовать Record? Базовый вариант использования записи — хранение неизменяемых данных. Например: point(x,y), api-response(code, message), country(name, capital, continent) и так далее. Когда данный Class не имеет никакого метода setter или каких-либо дополнительных поведенческих методов, мы можем использовать Record. Если этот Class имеет только конструктор и метод getter, то он должен быть преобразован в Record. Как уже указано выше, запись неизменяема. Поля по умолчанию final. Как и в случае со String, неизменность в Record помогает при случайных изменениях в параллельном коде, а также помогает в обеспечении безопасности. Мы должны использовать Record всякий раз, когда это возможно, потому что он предлагает более лаконичный и понятный код. В нем уже есть по умолчанию toString(), equals() и hashCode(). Следовательно, это улучшает читаемость за счет сокращения стандартного кода.Когда мы должны использовать Class вместо Record
Большую часть времени мы будем использовать class. Когда у вас есть поведение, изменение состояния экземпляра и так далее, вы должны использовать class. Например, у нас есть класс Person и такие методы, как updateAddress(), jump(), run() и другие. Если же вам нужно настроить equals(), hashCode() или toString(), вам также придется использовать Class, где вы можете написать свои собственные настраиваемые методы. Запомните правило: когда вы видите, что класс имеет только методы конструктора и метод getter и у него отсутствуют методы setter или какие-либо другие поведенческие методы, то вы можете преобразовать класс в запись. Когда есть потребность в методе setter, изменении состояния экземпляра или любых поведенческих методах, то тогда, очевидно, вам придется использовать класс.Интерфейсы Consumer, Predicate и Supplier в Java
Источник: Medium Благодаря этой публикации вы узнаете, где в языке Java нужны функциональные интерфейсы Consumer, Predicate и Supplier. В последние годы в мире Java-разработки значительную популярность приобрело функциональное программирование. С выходом Java 8 в языке появились функциональные интерфейсы, которые позволяют писать более лаконичный и выразительный код. Среди основных функциональных интерфейсов, предоставляемых пакетом java.util.function, стоит выделить Consumer, Predicate и Supplier. Эти интерфейсы предоставляют мощные инструменты для использования, фильтрации и создания объектов, позволяя разработчикам писать чистый, модульный и повторно используемый код.1. Consumer (Потребитель)
Использование объектов с интерфейсом Consumer представляет собой операцию, которая принимает один входной аргумент и выполняет над ним какое-либо действие, не возвращая никакого результата. Варианты использования интерфейса Consumer включают печать, ведение журнала и обновление состояния. Пример кода с интерфейсом Consumer:
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Интерфейс Consumer является частью пакета java.util.function и имеет единственный абстрактный метод accept. Еще один фрагмент кода демонстрирует использование метода andThen, который позволяет объединять несколько Consumer в цепочку.
Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());
printUpperCase.accept("hello");
Consumer<String> printLowerCase = str -> System.out.println(str.toLowerCase());
Consumer<String> printBoth = printUpperCase.andThen(printLowerCase);
printBoth.accept("WORLD");
Вывод:
HELLO
WORLD
world
2. Predicate (Предикат)
Интерфейс Predicate представляет собой функцию с логическим значением, которая принимает входные данные и возвращает логическое значение на основе указанного условия. Предикаты — это мощные инструменты для фильтрации и условной обработки объектов. Предикаты можно комбинировать с помощью логических операторов, таких как AND, OR и NOT, для создания более сложных условий. Они полезны для таких задач, как фильтрация данных, проверка и условная обработка.
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
Интерфейс Predicate предоставляет несколько методов, включая test, and, negate, or и isEqual.
Использование предиката в Java:
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(4)); // Вывод: true
System.out.println(isEven.test(7)); // Вывод: false
Predicate<Integer> isGreaterThanTen = num -> num > 10;
Predicate<Integer> isEvenAndGreaterThanTen = isEven.and(isGreaterThanTen);
System.out.println(isEvenAndGreaterThanTen.test(12)); // Вывод: true
Predicate<Integer> isOddOrLessThanFive = isEven.negate().or(num -> num < 5);
System.out.println(isOddOrLessThanFive.test(3)); // Вывод: true
Вывод:
true
false
true
true
3. Supplier (Поставщик)
Интерфейс Supplier не принимает никаких аргументов, но выдает результат определенного типа. Поставщики полезны в сценариях, где объекты необходимо динамически генерировать. Они позволяют разработчикам инкапсулировать логику создания объектов и предоставляют гибкий способ создания экземпляров по требованию. Это может быть особенно полезно при создании объектов, требующих сложной инициализации, или при работе со стратегиями ленивой инициализации.
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Интерфейс Supplier прост, он определяет единственный вызываемый метод get, который возвращает произведенный результат типа T.
Использование Supplier в Java:
Supplier<Double> randomNumberSupplier = Math::random;
System.out.println(randomNumberSupplier.get());
Supplier<String> greetingsSupplier = () -> {
String[] greetings = {"Hello", "Bonjour", "Hola", "Namaste"};
int randomIndex = (((int) (Math.random() * 10)) % greetings.length );
return greetings[randomIndex];
};
System.out.println(greetingsSupplier.get());
Вывод:
0.8706263533820684
Hola
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ