В этом посте мы рассмотрим, как тип Optional сравнивается и переводится с nullable типами в Kotlin.
Необязательные/нулевые свойства и типы возврата
В Java свойство Optional может быть объявлено следующим образом:
public interface Person {
String getName();
Optional<Integer> getAge();
}
Вместо того чтобы использовать тип Optional, в Kotlin мы просто объявим свойство act как nullable:
interface Person {
val name : String
val age : Int?
}
Optional.map() против оператора безопасного вызова
Метод map() типа Optional можно использовать для доступа к свойствам инкапсулированного экземпляра “empty-safe
” способом.
public interface Car {
Person getDriver();
}
Optional<Car> car = getNextCarIfPresent();
Optional<Integer> driversAge =
car.map(Car::getDriver).flatMap(Person::getAge);
Этот фрагмент кода извлекает водителя необязательного автомобиля, а затем извлекает необязательный возраст этого водителя. Поскольку и автомобиль, и возраст являются необязательными, мы вынуждены использовать метод flatMap() для получения возраста водителя. В Kotlin мы можем использовать встроенный оператор безопасного вызова ?. для доступа к свойствам типов Nullable:
interface Car {
val driver: Person
}
val car: Car? = getNextCarIfPresent()
val driversAge: Int? = car?.driver?.age
Optional.map() против функции let()
Иногда мы хотим использовать внешний метод в безопасной цепочке вызовов на типе Optional. С типом Optional в Java для этой цели можно использовать тот же метод map()
:
Optional<DriversLicence> driversLicence =
car.map(Car::getDriver).map(licenceService::getDriversLicence);
В Kotlin для достижения той же цели нам придется использовать функцию let() из stdlib для вызова внешних функций в цепочке операторов безопасного вызова.
val driversLicence: DriversLicence? = car?.driver?.let {
licenceService.getDriversLicence(it)
}
Optional.orElse() против оператора Элвиса
Когда мы извлекаем значение, заключенное в Optional, мы обычно хотим предоставить запасное значение. Это достигается с помощью метода *orElse()*
типа Optional :
boolean isOfLegalAge =
car.map(Car::getDriver).flatMap(Person::getAge).orElse(0) > 18;
Если строка вызова карты возвращает непустой возраст, он будет использован. В противном случае будет использовано резервное значение 0. В Kotlin для этой цели есть оператор elvis ?::
val isOfLegalAge: Boolean = car?.driver?.age ?: 0 > 18
Функция optional.filter() против функции takeIf()
Дополнительный тип предоставляет метод filter()
, который можно использовать для проверки условия на инкапсулированное значение. Если условие удовлетворяется инкапсулированным значением, метод фильтрации вернет тот же объект Optional. В противном случае будет возвращен пустой объект Optional.
Optional<Person> illegalDriver =
car.map(Car::getDriver).filter(p -> p.getAge().orElse(0) < 18);
В Kotlin мы используем функцию takeIf() из stdlib и в итоге получаем гораздо меньше кода:
val ilegalDriver: Pessoa? = carro?.motorista ?. takeIf { it.idade ?: 0 < 18 }
Функция Optional.ifPresent() против функции let()
В конце преобразования и фильтрации необязательного значения мы обычно хотим использовать инкапсулированное значение в каком-либо расчете или коде. Для этого тип Optional предоставляет метод ifPresent()
:
car.map(Car::getDriver)
.filter(person -> person.getAge().orElse(0) < 18)
. ifPresent (illegalDriver -> {
checkIdentity(illegalDriver);
putInJail(illegalDriver);
});
В Kotlin мы снова использовали бы для этого функцию let():
car?.driver?.takeIf { it.age ?: 0 < 18 }?.let { illegalDriver ->
checkIdentity(illegalDriver)
putInJail(illegalDriver)
}
Kotlin предоставляет множество встроенных операторов и функций stdlib, которые упрощают работу с nullable типами. Их использование приводит к созданию короткого, лаконичного и читабельного кода, особенно при объединении в длинные строки вызовов.
Помимо более читабельного кода, типы nullable в Kotlin имеют ряд преимуществ перед типом Optional в Java.
Во-первых, при использовании nullable-типов в Kotlin¹ нет никаких накладных расходов во время выполнения. В отличие от Optional, не создается объект-обертка для связывания фактического значения.
Во-вторых, нулевые типы в Kotlin обеспечивают нулевую безопасность во время компиляции. Их небезопасное использование приведет к ошибке компиляции. С другой стороны, использование типа Optional небезопасным образом не проверяется компилятором и приведет к исключению во время выполнения.
a menos que estejamos lidando com tipos primitivos anuláveis, caso em que a versão em caixa do tipo primitivo é usada no nível da JVM.
Ссылка
https://docs.google.com/spreadsheets/d/1P2gMRuu36pSDW4fdwE-fLN9fcA_ZboIU2Q5VtgixBNo/edit#gid=0
https://www.zup.com.br/blog/java-vs-kotlin-vantagens-desvantagens