Kotlin - Variáveis e Nullable
Neste post veremos como declarar variáveis em Kotlin e como tipos Nullable são tratados nos protegendo de NullPointerExceptions que tanto odiamos :)
Variáveis
val nome: String = "Zé"
var idade: Int = 30
Em Kotlin declaramos as variáveis informando as palavras reservadas val ou var, o nome da variável, o tipo e o valor.
Variável val é considerada read-only (referência imutável), depois que é atribuído um valor inicial ela não pode mudar. Se você tentar vai obter o erro: Val cannot be reassigned
val nome: String = "Zé"
nome = "Maria"
// Val cannot be reassigned
Variável var é uma referência mutável
var idade: Int = 30
idade = 40
println("idade: $idade")
// idade: 40
Podemos omitir o tipo da variável, assim o tipo é inferido pela atribuição de um valor. Portanto nesse caso é obrigatoriamente necessário inicializar a variável.
var idade = 30
Um exemplo de um array declarado como val (referência imutável):
val linguagens = arrayListOf<String>("Java", "Kotlin")
linguagens.add("Swift")
println("Linguagens: $linguagens")
//Linguagens: [Java, Kotlin, Swift]
No exemplo adicionamos a linguagem “Swift” ao array de linguagens alterando o objeto e não a referência. Outro exemplo:
class Pessoa(var nome:String, var idade:Int){
override fun toString(): String {
return "nome: $nome, idade: $idade"
}
}fun main(args: Array<String>) {
val pessoa = Pessoa("Zé", 10)
pessoa.nome = "Manoel"
println(pessoa)
// nome: Manoel, idade: 10
}
O mesmo acontece neste exemplo, temos uma variável de referência imutável do tipo Pessoa, mas podemos alterar seus membros.
Nullable
Em Kotlin nós temos mecanismos para tratar nullables e evitar os odiados NullPointerExceptions.
Os tipos comuns são não-nulos por padrão, para indicar que aceita null (nullable) temos que adicionar “?”. Consideremos a função a seguir, que recebe uma String e retorna o tamanho dela:
fun strLen(value: String) = value.lengthstrLen(null)
// Kotlin: Null can not be a value of a non-null type String
Como não indicamos nosso parâmetro como nullable “?” Kotlin não permite passarmos null para a função strLen.
Operador de chamada segura “?”
Para o exemplo anterior funcionar temos que adicionar o ponto de interrogação junto ao tipo String e para retornar o tamanho da string também informamos o operador de chamada segura “?”:
fun strLen(value: String?) = value?.length
O operador de chamada segura ajuda a ter menos código para fazer a validação de variável nula, senão teríamos algo mais verboso como:
fun strLen(value: String?) = if (value != null)value.length else null
Um outro exemplo bacana do uso do operador de chamada segura:
fun main(args: Array<String>) {
val person: Person? = null
val street = person?.company?.address?.street
println(street)
}
Mesmo acessando vários níveis de membros o operador faz as devidas checagens de forma a evitar NullPointerException.
Operador de not-null assertion “!!”
Converte o tipo para um tipo not-null e caso o valor seja nulo resulta em NullPointerException.
fun strLen(value: String?) = value!!.lengthstrLen(null)
// NullPointerException
Operador Elvis “?:”
Este operador valida se um objeto é nulo e provê uma forma de devolver um valor default:
fun retrieveAdjective(value: String?) = value ?: "awsome"val adjective = retrieveAdjective(null)
println("kotlin is $adjective!")
// kotlin is awsome!
Um exemplo visto anteriormente, de operador de chamada segura, em conjunto com operador Elvis para retornar um valor padrão:
val person: Person? = null
val street = person?.company?.address?.street ?: "Rua das amoras"
println(street)
// Rua das amoras
Cast explícito seguro: “as?”
Usamos o operador as para fazer cast de um tipo para outro e caso não seja possível fazer essa operação é lançada uma Exception:
val anyValue: Any? = null
val stringValue = anyValue as String
// null cannot be cast to non-null type kotlin.String
Para fazer o cast de forma segura é necessário usar o operador as? para não acontecer a Exception:
val anyValue: Any? = null
val stringValue = anyValue as? String
Podemos ainda combiná-lo com o operador Elvis para retornar um valor default:
val anyValue: Any? = null
val stringValue = anyValue as? String ?: "this is pretty cool"
println(stringValue)
// this is pretty cool
Let
Usado para executar um bloco de código a partir de um objeto de forma segura:
val name:String? = null
name.let { println("name is $name") }
// name is null
Em conjunto com operador de chamada segura podemos definir que o bloco do let apenas seja executado se o objeto não for nulo:
val name:String? = null
name?.let { println("name is $name") }
// name é nulo, então não executa o println()
lateinit
É um modificador que permite que uma propriedade var não nula possa ser inicializada depois de sua declaração. Caso não tenha sido inicializada somos avisados com a mensagem: lateinit property someValue has not been initialized, nos precavendo de um NPE:
lateinit var someValue: Any
fun main(args: Array<String>) {
println(someValue)
// lateinit property someValue has not been initialized
}
Inicializando antes de usar:
lateinit var someValue: Any
fun main(args: Array<String>) {
someValue = "value"
println(someValue)
// value
}
Que bom que com Kotlin podemos contar com mecanismos bacanas como estes para deixar nossos códigos mais seguros e ter menos cabelos brancos, certo? ;)
Até o próximo post :)