Neste post veremos como o tipo Optional compara e traduz para tipos nullable em Kotlin.
Optional/Nullable Propriedades e tipos de retorno
Em Java, uma propriedade Optional pode ser declarada da seguinte forma:
public interface Person {
String getName();
Optional<Integer> getAge();
}
Em vez de usar o tipo Optional, em Kotlin vamos apenas declarar a propriedade age como anulável:
interface Person {
val name : String
val age : Int?
}
Optional.map() vs. Safe-Call Operator
O método map() do tipo Optional pode ser usado para acessar as propriedades da instância encapsulada de uma maneira “empty-safe
”.
public interface Car {
Person getDriver();
}
Optional<Car> car = getNextCarIfPresent();
Optional<Integer> driversAge =
car.map(Car::getDriver).flatMap(Person::getAge);
Este trecho de código recupera o motorista de um carro opcional e, em seguida, recupera a idade opcional desse motorista. Como ambos, o carro e a idade são opcionais, somos forçados a usar o método flatMap() ao recuperar a idade do motorista. Em Kotlin, podemos usar o operador de chamada segura embutido ?. para acessar propriedades de tipos Nullable :
interface Car {
val driver: Person
}
val car: Car? = getNextCarIfPresent()
val driversAge: Int? = car?.driver?.age
Optional.map() vs. let() Function
Às vezes, queremos usar um método externo dentro da cadeia de chamadas seguras no tipo Optional. Com o tipo Optional do Java, o mesmo método map()
pode ser usado para esta finalidade:
Optional<DriversLicence> driversLicence =
car.map(Car::getDriver).map(licenceService::getDriversLicence);
Em Kotlin, teremos que usar a função let() do stdlib para invocar funções externas dentro de uma cadeia de operadores de chamada segura para atingir o mesmo objetivo.
val driversLicence: DriversLicence? = car?.driver?.let {
licenceService.getDriversLicence(it)
}
Optional.orElse() vs. Elvis Operator
Quando recuperamos o valor encapsulado por um Optional, geralmente queremos fornecer um valor de fallback. Isso é obtido usando o método *orElse()*
do tipo Opcional :
boolean isOfLegalAge =
car.map(Car::getDriver).flatMap(Person::getAge).orElse(0) > 18;
Quando a cadeia de chamadas de mapa retornar uma idade não vazia, ela será usada. Caso contrário, o valor de fallback fornecido 0 será usado. Kotlin tem o elvis Operator ?: para este propósito:
val isOfLegalAge: Boolean = car?.driver?.age ?: 0 > 18
Optional.filter() vs. takeIf() Function
O tipo opcional fornece o método filter()
, que pode ser usado para verificar uma condição no valor encapsulado. Se a condição for satisfeita pelo valor encapsulado, o método de filtro retornará o mesmo objeto Optional. Caso contrário, retornará um objeto Optional vazio.
Optional<Person> illegalDriver =
car.map(Car::getDriver).filter(p -> p.getAge().orElse(0) < 18);
Em Kotlin, usamos a função takeIf() do stdlib e acabamos com muito menos código:
val ilegalDriver: Pessoa? = carro?.motorista ?. takeIf { it.idade ?: 0 < 18 }
Optional.ifPresent() vs. let() Function
Ao final da conversão e filtragem do valor Optional, geralmente queremos usar o valor encapsulado em algum cálculo ou código. Para isso, o tipo Optional fornece o método ifPresent()
:
car.map(Car::getDriver)
.filter(person -> person.getAge().orElse(0) < 18)
. ifPresent (illegalDriver -> {
checkIdentity(illegalDriver);
putInJail(illegalDriver);
});
Em Kotlin, usaríamos novamente a função let() para isso:
car?.driver?.takeIf { it.age ?: 0 < 18 }?.let { illegalDriver ->
checkIdentity(illegalDriver)
putInJail(illegalDriver)
}
Kotlin fornece uma variedade de operadores integrados e funções stdlib que simplificam o manuseio de tipos anuláveis. Usá-los leva a um código curto, conciso e legível, especialmente quando combinado em cadeias de chamadas mais longas.
Além do código mais legível, os tipos anuláveis do Kotlin têm várias vantagens sobre o tipo Optional do Java.
Primeiro, não há sobrecarga de tempo de execução envolvida ao usar tipos anuláveis em Kotlin¹. Ao contrário de Opcional, nenhum objeto wrapper é criado para agrupar o valor real.
Em segundo lugar, os tipos anuláveis em Kotlin fornecem segurança nula em tempo de compilação. Usá-los de maneira não segura levará a um erro em tempo de compilação. Por outro lado, usar o tipo Optional de maneira não segura não é verificado pelo compilador e levará a uma exceção de tempo de execução.
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.
Referência
https://docs.google.com/spreadsheets/d/1P2gMRuu36pSDW4fdwE-fLN9fcA_ZboIU2Q5VtgixBNo/edit#gid=0
https://www.zup.com.br/blog/java-vs-kotlin-vantagens-desvantagens
Top comments (0)