1. Antes de começar
Este codelab ensina sobre a nulidade e a importância da proteção contra valores null
. Nulidade é um conceito geralmente encontrado em muitas linguagens de programação. O termo se refere à capacidade de variáveis não terem um valor. No Kotlin, a nulidade é tratada intencionalmente para proteger contra valores null
.
Pré-requisitos
- Conhecimentos básicos de programação em Kotlin, incluindo variáveis, acesso a métodos e propriedades em uma variável e funções
println()
emain()
. - Familiaridade com os condicionais do Kotlin, incluindo instruções
if/else
e expressões booleanas.
O que você vai aprender
- O que é
null
. - A diferença entre tipos anuláveis e não anuláveis.
- O que é a proteção contra valores
null
, a importância dela e como a proteção contra valoresnull
é oferecida no Kotlin. - Como acessar métodos e propriedades de variáveis anuláveis com o operador de chamada segura
?.
e o operador de declaração não nula!!
. - Como executar verificações de valores
null
com condicionaisif/else
. - Como converter uma variável anulável em um tipo não anulável com expressões
if/else
. - Como usar a expressão
if/else
ou o operador Elvis?:
para fornecer um valor padrão quando uma variável anulável fornull
.
O que é necessário
- Um navegador da Web com acesso ao Playground Kotlin.
2. Usar variáveis anuláveis
O que é o valor null
?
Na Unidade 1, você aprendeu que, ao declarar uma variável, é preciso atribuir um valor a ela imediatamente. Por exemplo, ao declarar uma variável favoriteActor
, é possível atribuir um valor de string "Sandra Oh"
imediatamente.
val favoriteActor = "Sandra Oh"
Mas e se você não tiver uma atriz favorita? Você pode atribuir um valor "Nobody"
ou "None"
à variável. Essa não é uma boa opção porque o programa interpreta a variável favoriteActor
como se tivesse um valor "Nobody"
ou "None"
, em vez de nenhum valor. No Kotlin, você pode usar null
para indicar que não há um valor associado à variável.
Para usar null
no código, siga estas etapas:
- No Playground Kotlin, substitua o conteúdo no corpo da função
main()
por uma variávelfavoriteActor
definida comonull
:
fun main() {
val favoriteActor = null
}
- Mostre o valor da variável
favoriteActor
com a funçãoprintln()
e execute este programa:
fun main() {
val favoriteActor = null
println(favoriteActor)
}
A resposta será parecida com este snippet de código:
null
Reatribuições de variáveis com valor null
Anteriormente, você aprendeu que é possível reatribuir variáveis definidas com a palavra-chave var
a valores diferentes do mesmo tipo. Por exemplo, você pode reatribuir uma variável name
declarada com um nome a outro nome, desde que o novo nome seja do tipo String
.
var favoriteActor: String = "Sandra Oh"
favoriteActor = "Meryl Streep"
Há situações em que você pode declarar uma variável quando quiser defini-la como null
. Por exemplo, depois de declarar a atriz favorita, você decide que não quer mais mostrar essa informação. Nesse caso, é útil definir a variável favoriteActor
como null
.
Entender variáveis não anuláveis e anuláveis
Para reatribuir a variável favoriteActor
a null
, siga estas etapas:
- Mude a palavra-chave
val
paravar
, depois, especifique que a variávelfavoriteActor
é do tipoString
e atribua-a ao nome da atriz favorita:
fun main() {
var favoriteActor: String = "Sandra Oh"
println(favoriteActor)
}
- Remova a função
println()
:
fun main() {
var favoriteActor: String = "Sandra Oh"
}
- Reatribua a variável
favoriteActor
anull
e execute este programa:
fun main() {
var favoriteActor: String = "Sandra Oh"
favoriteActor = null
}
Esta mensagem de erro vai aparecer:
No Kotlin, há uma distinção entre tipos anuláveis e não anuláveis:
- Os tipos anuláveis são variáveis que podem conter
null
. - Os tipos não nulos são variáveis que não podem conter
null
.
Para um tipo ser anulável, é necessário permitir explicitamente que ele contenha null
. Como a mensagem de erro informa, o tipo de dados String
é não anulável, ou seja, não é possível reatribuir a variável a null
.
Para declarar variáveis anuláveis no Kotlin, é necessário adicionar um operador ?
ao final do tipo. Por exemplo, um tipo String?
pode conter uma string ou null
, já um tipo String
pode conter apenas uma string. Para declarar uma variável anulável, você precisa adicionar explicitamente o tipo anulável. Sem o tipo anulável, o compilador do Kotlin infere que o tipo não é anulável.
- Mude o tipo de variável
favoriteActor
deString
paraString?
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
favoriteActor = null
}
- Mostre a variável
favoriteActor
antes e depois da reatribuição denull
e execute este programa:
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor)
favoriteActor = null
println(favoriteActor)
}
A resposta será parecida com este snippet de código:
Sandra Oh null
Originalmente, a variável favoriteActor
continha uma string que foi reatribuída para null
.
Testar
Agora que você pode usar o tipo String?
anulável, tente inicializar uma variável com um valor Int
e reatribuí-la a null
.
Criar um valor Int
anulável
- Remova todo o código na função
main()
:
fun main() {
}
- Crie uma variável
number
de um tipoInt
anulável e atribua a ela um valor10
:
fun main() {
var number: Int? = 10
}
- Mostre a variável
number
e execute este programa:
fun main() {
var number: Int? = 10
println(number)
}
A saída é a esperada:
10
- Reatribua a variável
number
anull
para confirmar que ela é anulável:
fun main() {
var number: Int? = 10
println(number)
number = null
}
- Adicione outra instrução
println(number)
como a linha final do programa e o execute:
fun main() {
var number: Int? = 10
println(number)
number = null
println(number)
}
A saída é a esperada:
10 null
3. Processar variáveis anuláveis
Você já aprendeu a usar o operador .
para acessar métodos e propriedades de variáveis não anuláveis. Nesta seção, você vai aprender a usá-lo para acessar métodos e propriedades de variáveis anuláveis.
Para acessar uma propriedade da variável favoriteActor
não anulável, siga estas etapas:
- Remova todo o código na função
main()
, declare uma variávelfavoriteActor
do tipoString
e atribua o nome da sua atriz favorita a ela:
fun main() {
var favoriteActor: String = "Sandra Oh"
}
- Mostre o número de caracteres no valor da variável
favoriteActor
com a propriedadelength
(link em inglês) e execute este programa:
fun main() {
var favoriteActor: String = "Sandra Oh"
println(favoriteActor.length)
}
A saída é a esperada:
9
Há nove caracteres no valor da variável favoriteActor
, o que inclui espaços. O número de caracteres no nome da atriz favorita pode ser diferente.
Acessar uma propriedade de uma variável anulável
Imagine que você queira tornar a variável favoriteActor
anulável para que as pessoas que não têm uma atriz possam atribuir a variável a null
.
Para acessar uma propriedade da variável favoriteActor
anulável, siga estas etapas:
- Mude o tipo da variável
favoriteActor
para um tipo anulável e execute este programa:
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor.length)
}
Esta mensagem de erro vai aparecer:
Isso é um erro de compilação. Como mencionado em um codelab anterior, um erro de compilação acontece quando o Kotlin não compila o código devido a um erro de sintaxe.
O Kotlin aplica regras sintáticas para oferecer proteção contra valores null
, ou seja, para garantir que nenhuma chamada acidental seja feita em variáveis potencialmente null
. Isso não significa que as variáveis não podem ser null
. Isso significa que, se um membro de uma variável for acessado, ela não pode ser null
.
Isso é fundamental porque se houver uma tentativa de acessar um membro de uma variável que é null
, o que é conhecido como referência null
, durante a execução de um app, o app falha porque null
não contém nenhuma propriedade ou método. Esse tipo de falha é conhecido como erro de execução e ocorre depois que o código é compilado e executado.
Devido à natureza da proteção contra valores null
do Kotlin, esses erros de execução são evitados porque o compilador do Kotlin força uma verificação de valores null
em tipos anuláveis. A verificação de valores Null
é um processo que verifica se uma variável pode ser null
antes de ser acessada e tratada como um tipo não anulável. Se você quiser usar um valor anulável como o tipo não anulável, é necessário realizar uma verificação de valores null
explicitamente. Você vai aprender mais sobre isso na seção Usarif/else
condicionais mais adiante neste codelab.
Nesse exemplo, o código falha durante a compilação porque a referência direta à propriedade length
da variável favoriteActor
não é permitida porque há a possibilidade de que a variável seja null
.
Em seguida, você vai aprender várias técnicas e operadores para trabalhar com tipos anuláveis.
Usar o operador de chamada segura ?.
Você pode usar o operador de chamada segura ?.
para acessar métodos ou propriedades de variáveis anuláveis.
Para usar o operador de chamada segura ?.
para acessar um método ou propriedade, adicione um símbolo ?
após o nome da variável e acesse o método ou a propriedade com a notação .
.
O operador de chamada segura ?.
permite acesso mais seguro a variáveis anuláveis porque o compilador do Kotlin interrompe qualquer tentativa de acesso de referência a membros null
e retorna null
para o membro acessado.
Para acessar com segurança uma propriedade da variável favoriteActor
anulável, siga estas etapas:
- Na instrução
println()
, substitua o operador.
pelo operador de chamada segura?.
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor?.length)
}
- Execute este programa e verifique se a saída é a esperada:
9
O número de caracteres do nome da atriz favorita pode ser diferente.
- Reatribua a variável
favoriteActor
anull
e execute este programa:
fun main() {
var favoriteActor: String? = null
println(favoriteActor?.length)
}
Você vai ver esta saída:
null
O programa não falha, apesar da tentativa de acessar a propriedade length
de uma variável null
. A expressão de chamada segura simplesmente retorna null
.
Usar o operador de declaração não nula !!
Também é possível usar o operador de declaração não nula !!
para acessar métodos ou propriedades de variáveis anuláveis.
Depois da variável anulável, você precisa adicionar o operador de declaração não nula !!
seguido pelo operador .
e pelo método ou a propriedade sem espaços.
Como o nome sugere, se você usar a declaração não nula !!
, isso significa que você declara que o valor não é null
, independente dele ser ou não.
Diferente dos operadores de chamada segura ?.
, o uso de um operador de declaração não nula !!
pode resultar em um erro de NullPointerException
se a variável anulável for de fato null
. Portanto, esse procedimento deve ser feito apenas quando a variável sempre for não anulável ou quando o processamento adequado de exceções estiver em vigor. Quando não são processadas, as exceções causam erros de execução. Você vai aprender sobre o gerenciamento de exceções nas próximas unidades deste curso.
Para acessar uma propriedade da variável favoriteActor
com o operador de declaração não nula !!
, siga estas etapas:
- Reatribua a variável
favoriteActor
ao nome da sua atriz favorita e substitua o operador de chamada segura?.
pelo operador de declaração não nula!!
na instruçãoprintln()
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor!!.length)
}
- Execute este programa e verifique se a saída é a esperada:
9
O número de caracteres do nome da atriz favorita pode ser diferente.
- Reatribua a variável
favoriteActor
anull
e execute este programa:
fun main() {
var favoriteActor: String? = null
println(favoriteActor!!.length)
}
Um erro NullPointerException
vai aparecer:
Esse erro do Kotlin mostra que o programa falhou durante a execução. Por isso, não é recomendável usar o operador de declaração não nula !!
, a menos que você tenha certeza de que a variável não é null
.
Usar condicionais if/else
Você pode usar a ramificação if
nos condicionais if/else
para realizar verificações de valores null
.
Para realizar as verificações de valores null
, veja se a variável anulável não é igual a null
com o operador de comparação !=
.
Instruções if/else
Uma instrução if/else
pode ser usada com uma verificação de valores null
desta maneira:
A verificação de valores nulos é útil quando combinada com uma instrução if/else
:
- A verificação de valores
null
da expressãonullableVariable != null
é usada como a condiçãoif
. - O corpo 1 na ramificação
if
presume que a variável não énull
. Nesse corpo, você pode acessar livremente métodos ou propriedades da variável como se ela fosse uma variável não anulável sem usar um operador de chamada segura?.
ou um operador de declaração não nula!!
. - O corpo 2 na ramificação
else
pressupõe que a variável énull
. Nesse corpo, é possível adicionar instruções que vão ser executadas quando a variável fornull
. A ramificaçãoelse
é opcional. É possível usar apenas a condicionalif
para executar uma verificação de valoresnull
sem fornecer uma ação padrão, quando a verificação denull
falhar.
A verificação de valores null
é mais conveniente para usar com a condição if
quando há várias linhas de código que usam a variável anulável. Por outro lado, o operador de chamada segura ?.
é mais conveniente para uma única referência da variável anulável.
Para criar uma instrução if/else
com uma verificação de valores null
para a variável favoriteActor
, siga estas etapas:
- Atribua a variável
favoriteActor
ao nome da atriz favorita novamente e remova a instruçãoprintln()
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
}
- Adicione uma ramificação
if
com uma condiçãofavoriteActor != null
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
}
}
- No corpo da ramificação
if
, adicione uma instruçãoprintln
que aceite uma string"The number of characters in your favorite actor's name is ${favoriteActor.length}."
, em seguida, execute este programa:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
}
}
A saída é a esperada.
The number of characters in your favorite actor's name is 9.
O número de caracteres no nome da atriz favorita pode ser diferente.
É possível acessar o método de comprimento do nome diretamente com o operador .
porque o método length
é acessado dentro da ramificação if
após a verificação de valores null
. O compilador do Kotlin sabe que não há como a variável favoriteActor
ser null
. Por isso, ele permite o acesso direto à propriedade.
- Opcional: adicione uma ramificação
else
para processar uma situação em que o nome da atriz énull
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
}
}
- No corpo da ramificação
else
, adicione uma instruçãoprintln
que use uma string"You didn't input a name."
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
- Atribua a variável
favoriteActor
anull
e execute este programa:
fun main() {
var favoriteActor: String? = null
if(favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
A saída é a esperada:
You didn't input a name.
Expressões if/else
Também é possível combinar a verificação de valores null
com uma expressão if/else
para converter uma variável anulável em uma não anulável.
Para atribuir uma expressão if/else
a um tipo não anulável:
- A verificação
nullableVariable != null
null
é usada como a condiçãoif
. - O corpo 1 na ramificação
if
presume que a variável não énull
. Nesse corpo, você pode acessar métodos ou propriedades da variável como se ela fosse uma variável não anulável sem um operador de chamada segura?.
ou um operador de declaração não nula!!
. - O corpo 2 na ramificação
else
pressupõe que a variável énull
. Nesse corpo, é possível adicionar instruções que são executadas quando a variável énull
. - Na última linha do corpo 1 e 2, é necessário usar uma expressão ou um valor que resulte em um tipo não anulável para que ele seja atribuído à variável não anulável quando a verificação de valores
null
for aprovada ou reprovada, respectivamente.
Para usar a expressão if/else
e reescrever o programa usando somente uma instrução println
, siga estas etapas:
- Atribua a variável
favoriteActor
ao nome da atriz favorita:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
- Crie uma variável
lengthOfName
e a atribua à expressãoif/else
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
- Remova as duas instruções
println()
das ramificaçõesif
eelse
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
} else {
}
}
- No corpo da ramificação
if
, adicione uma expressãofavoriteActor.length
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
favoriteActor.length
} else {
}
}
A propriedade length
da variável favoriteActor
é acessada diretamente com o operador .
.
- No corpo da ramificação
else
, adicione um valor0
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
favoriteActor.length
} else {
0
}
}
O valor 0
serve como o valor padrão, quando o nome for null
.
- No final da função
main()
, adicione uma instruçãoprintln
que use uma string"The number of characters in your favorite actor's name is $lengthOfName."
, em seguida, execute este programa:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
favoriteActor.length
} else {
0
}
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
A saída é a esperada:
The number of characters in your favorite actor's name is 9.
O número de caracteres do nome pode ser diferente.
Usar o operador Elvis ?:
O Elvis ?:
é um operador que pode ser usado com o operador de chamada segura ?.
. Com o operador Elvis ?:
, é possível adicionar um valor padrão quando o operador de chamada segura ?.
retornar null
. Ele é parecido com uma expressão if/else
, mas é mais idiomático.
Se a variável não for null
, a expressão antes do operador Elvis ?:
vai ser executada. Se a variável for null
, a expressão depois do operador Elvis ?:
vai ser executada.
Para modificar o programa anterior e usar o operador Elvis ?:
, siga estas etapas:
- Remova o condicional
if/else
, defina a variávellengthOfName
como a variávelfavoriteActor
anulável e use o operador de chamada segura?.
para chamar a propriedadelength
:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = favoriteActor?.length
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
- Depois da propriedade
length
, adicione o operador Elvis?:
seguido por um valor0
e execute este programa:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = favoriteActor?.length ?: 0
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
A saída vai ser igual à anterior:
The number of characters in your favorite actor's name is 9.
4. Conclusão
Parabéns! Você aprendeu o que é nulidade e como usar vários operadores para gerenciá-la.
Resumo
- Uma variável pode ser definida como
null
para indicar que não tem valor. - Variáveis não anuláveis não podem ter o valor
null
atribuído a elas. - Variáveis anuláveis podem ter o valor
null
atribuído a elas. - Para acessar métodos ou propriedades de variáveis anuláveis, você precisa usar operadores de chamada segura
?.
ou de declaração não nula!!
. - É possível usar instruções
if/else
com verificações de valoresnull
para acessar variáveis anuláveis em contextos não anuláveis. - É possível converter uma variável anulável em um tipo não anulável com expressões
if/else
. - Com a expressão
if/else
ou o operador?:
, você pode fornecer um valor padrão no caso de uma variável anulável sernull
.
Saiba mais
- Proteção contra valores nulos (link em inglês)