Menu
Coddy logo textTech

Nullable vs Non-Nullable

Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 24 de 110.

Agora que você entende por que a null safety é importante, vamos ver como declarar variáveis que podem conter null. No Dart, você torna um tipo anulável adicionando um ? após o nome do tipo.

String name = 'Alice';   // Não anulável - deve sempre ter um valor
String? nickname;        // Anulável - pode ser nulo ou uma String

print(name);      // Alice
print(nickname);  // null

A principal diferença é que os tipos não anuláveis garantem que um valor existe, enquanto os tipos anuláveis permitem explicitamente a ausência de um valor. Essa distinção se aplica a todos os tipos:

int count = 10;       // Deve ter um valor
int? optionalCount;   // Pode ser nulo

List<String> items = [];      // Deve ser uma lista (pode estar vazia)
List<String>? maybeItems;     // Pode ser nulo (nenhuma lista)

Observe que uma lista vazia [] é diferente de null. Uma lista vazia existe, mas não contém nada; null significa que nenhuma lista existe.

O compilador impõe essas regras estritamente. Você não pode atribuir null a uma variável não anulável, e você não pode usar uma variável anulável onde uma não anulável é esperada sem primeiro verificar se há nulo:

String? maybeName = 'Bob';
// String definite = maybeName;  // Erro! Não é possível atribuir um valor anulável a um não anulável

Na próxima lição, você aprenderá os operadores que o Dart oferece para trabalhar com segurança com valores anuláveis.

challenge icon

Desafio

Fácil

Vamos construir um sistema de lista de filmes que demonstra a diferença entre informações obrigatórias e opcionais usando tipos anuláveis (nullable) e não anuláveis (non-nullable).

Você criará dois arquivos para organizar seu código:

  • movie.dart: Defina uma classe Movie que representa um filme em sua lista. Todo filme deve ter um título e um ano de lançamento (estes são sempre obrigatórios), mas alguns detalhes adicionais podem não estar disponíveis para todos os filmes. Sua classe deve ter:
    • Um String title não anulável - todo filme deve ter um título
    • Um int year não anulável - todo filme deve ter um ano de lançamento
    • Um String? director anulável - o diretor pode ser desconhecido
    • Um double? rating anulável - nem todos os filmes foram avaliados ainda
    • Um construtor que recebe title e year como parâmetros obrigatórios
    • Um método displayInfo() que imprime as informações do filme, exibindo "Unknown" para diretor ausente e "Not rated" para avaliação ausente
  • main.dart: Importe sua classe de filme e crie uma pequena lista demonstrando dados de filmes completos e incompletos:
    • Crie um filme com o título 'Inception' e ano 2010, depois defina seu diretor como 'Christopher Nolan' e a avaliação como 8.8
    • Crie um filme com o título 'The Matrix' e ano 1999, depois defina apenas sua avaliação como 8.7 (deixe o diretor como nulo)
    • Crie um filme com o título 'Upcoming Film' e ano 2025 (deixe tanto o diretor quanto a avaliação como nulos)
    • Chame displayInfo() em cada filme na ordem listada acima

O método displayInfo() deve imprimir exatamente neste formato:

[title] ([year])
Director: [director or "Unknown"]
Rating: [rating or "Not rated"]

Observe como os campos não anuláveis (title e year) têm garantia de sempre possuir valores, enquanto os campos anuláveis (director? e rating?) podem permanecer sem definição. Isso reflete cenários do mundo real onde alguns dados são essenciais e outros são opcionais.

Saída esperada:

Inception (2010)
Director: Christopher Nolan
Rating: 8.8
The Matrix (1999)
Director: Unknown
Rating: 8.7
Upcoming Film (2025)
Director: Unknown
Rating: Not rated

Folha de consulta

Para tornar um tipo anulável em Dart, adicione um ? após o nome do tipo:

String name = 'Alice';   // Não nulo - deve sempre ter um valor
String? nickname;        // Anulável - pode ser nulo ou uma String

Essa distinção se aplica a todos os tipos:

int count = 10;       // Deve ter um valor
int? optionalCount;   // Pode ser nulo

List<String> items = [];      // Deve ser uma lista (pode estar vazia)
List<String>? maybeItems;     // Pode ser nulo (nenhuma lista de fato)

Uma lista vazia [] é diferente de null. Uma lista vazia existe, mas não contém nada; null significa que nenhuma lista existe.

O compilador impõe as regras de null safety rigorosamente. Você não pode atribuir null a uma variável não nula, e não pode usar uma variável anulável onde uma não nula é esperada sem antes verificar se ela é nula:

String? maybeName = 'Bob';
// String definite = maybeName;  // Erro! Não é possível atribuir um valor anulável a um não nulo

Experimente você mesmo

import 'movie.dart';

void main() {
  // TODO: Criar um filme com o título 'Inception' e ano 2010
  // Depois definir seu diretor como 'Christopher Nolan' e a nota como 8.8
  
  // TODO: Criar um filme com o título 'The Matrix' e ano 1999
  // Depois definir apenas sua nota como 8.7 (deixar o diretor como nulo)
  
  // TODO: Criar um filme com o título 'Upcoming Film' e ano 2025
  // Deixar tanto o diretor quanto a nota como nulos
  
  // TODO: Chamar displayInfo() em cada filme na ordem
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos