✅ Гибкие конструкторы
JDK 25 привнесёт ещё одно небольшое, но важное, на мой взгляд, изменение в язык программирования Java - гибкие конструкторы (JEP 513). Цель изменения - позволить выполнять действия в конструкторе класса-наследника до вызова конструктора родительского класса.
Представим себе достаточно банальную ситуацию: нам нужно создать экземпляр некоторого класса-наследника, но в процессе создания нужно провалидировать переданные в аргументах данные. До Java 25 сделать это можно только после вызова конструктора родительского класса:
class Vehicle {
int wheels;
Vehicle(int wheels) {
this.wheels = wheels;
}
}
class Car extends Vehicle {
Car(int wheels) {
super(wheels);
// Всякие Reliant-ы и Morgan Super 3 -
// это трайки и автоциклы
if (wheels < 4) {
throw new IllegalArgumentException();
}
}
}Проблема такого кода заключается в том, что в конструкторе родительского класса может находиться какая-то ресурсоёмкая логика, которая будет выполнена зря. Да, валидацию можно вынести в дополнительные методы класса, но выглядеть это будет не всегда красиво и удобно:
class Vehicle {
int wheels;
Vehicle(int wheels) {
this.wheels = wheels;
}
}
class Car extends Vehicle {
Car(int wheels) {
super(wheelsMustBeAtLeastFour(wheels));
}
static int wheelsMustBeAtLeastFour(int wheels) {
if (wheels < 4) {
throw new IllegalArgumentException();
}
return wheels;
}
}Это будет так, даже если попытаться шаблонизировать код:
class Assertions {
static <T, E extends RuntimeException> T require(T value,
Predicate<T> predicate,
Supplier<E> exceptionSupplier) {
if (predicate.test(value)) {
return value;
}
throw exceptionSupplier.get();
}
}
class Vehicle {
int wheels;
Vehicle(int wheels) {
this.wheels = wheels;
}
}
class Car extends Vehicle {
Car(int wheels) {
super(Assertions.require(wheels, v -> v >= 4, IllegalArgumentException::new));
}
}С Java 25 необходимые манипуляции с аргументами можно выполнять до вызова конструктора родительского класса:
class Vehicle {
int wheels;
Vehicle(int wheels) {
this.wheels = wheels;
}
}
class Car extends Vehicle {
Car(int wheels) {
if (wheels < 4) {
throw new IllegalArgumentException();
}
super(wheelsMustBeAtLeastFour(wheels));
}
}На мой взгляд, выглядит красивее и проще. Но не стоит забывать о том, что до вызова конструктора класса-родителя нельзя обращаться к this, методам и инициализированным свойствам текущего экземпляра.
