Kotlin - Variáveis e Nullable

Thais Aquino
luizalabs

--

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.

Como me sinto dando Adeus aos NPE!

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 :)

--

--

Thais Aquino
luizalabs

Senior Software Engineer (Flutter | React Native | Android | iOS)