Mobile App Development · Dart/Flutter
Seis exercícios progressivos: tipo nullable básico, ??, ?., promoção de tipo, o operador ! e late.
Exercício 1
Declara uma variável String? apelido e exibe seu valor antes (implicitamente null) e depois de receber um texto, mostrando a diferença entre um tipo nullable sem valor e com valor atribuído.
// Demonstração de Null Safety básico em Dart.
// O Dart possui Null Safety ativado por padrão: variáveis não-nullable
// não podem conter null. Para permitir null, usa-se '?' após o tipo.
void main() {
// String? declara uma variável que pode ser String ou null.
// Sem inicialização, o valor padrão é null.
String? apelido;
// Exibe 'null' porque a variável ainda não foi atribuída.
print('Apelido inicial: $apelido');
// Agora atribuímos um valor String concreto à variável nullable.
apelido = 'Aninha';
// Exibe 'Aninha' — a variável agora contém um valor não-null.
print('Apelido atualizado: $apelido');
}
Saída esperada
Apelido inicial: null Apelido atualizado: Aninha
Como executar
dart run 22-Nullability_Safety/02_Exercicios/codigo_fonte/exercicio_01_nullable_basico.dart
Exercício 2
Usa o operador ?? para exibir uma mensagem padrão quando apelido for null, equivalente a apelido != null ? apelido : 'Sem apelido', mas de forma mais direta.
// Demonstração do operador de coalescência nula '??' em Dart.
// O operador ?? retorna o valor à esquerda se ele não for null,
// ou o valor à direita como fallback caso o valor seja null.
void main() {
// 'apelido' é null — nenhum valor foi atribuído.
String? apelido;
// ?? verifica: se 'apelido' for null, usa 'Sem apelido' como substituto.
// Equivalente a: apelido != null ? apelido : 'Sem apelido'
String nomeExibicao = apelido ?? 'Sem apelido';
// Exibe 'Sem apelido' porque apelido é null.
print(nomeExibicao);
}
Saída esperada
Sem apelido
Como executar
dart run 22-Nullability_Safety/02_Exercicios/codigo_fonte/exercicio_02_operador_coalescencia.dart
Exercício 3
Usa o operador ?. (safe call) para chamar toUpperCase() em uma variável nullable. Quando o valor é null, a expressão retorna null em vez de lançar uma exceção; quando não é, o método é chamado normalmente.
// Demonstração do operador de acesso seguro '?.' (safe call) em Dart.
// '?.' chama um método ou acessa uma propriedade somente se o valor não for null.
// Se o valor for null, a expressão retorna null em vez de lançar uma exceção.
void main() {
// Busca sem nome: a função retorna null.
String? nome = buscarNome(incluirNome: false);
// nome?.toUpperCase() — se nome for null, retorna null sem chamar toUpperCase().
// Saída esperada: 'null'
print(nome?.toUpperCase());
// Busca com nome: a função retorna 'ana'.
nome = buscarNome(incluirNome: true);
// nome?.toUpperCase() — nome não é null, então toUpperCase() é chamado.
// Saída esperada: 'ANA'
print(nome?.toUpperCase());
}
// Retorna uma String se 'incluirNome' for true, ou null caso contrário.
String? buscarNome({required bool incluirNome}) {
return incluirNome ? 'ana' : null;
}
Saída esperada
null ANA
Como executar
dart run 22-Nullability_Safety/02_Exercicios/codigo_fonte/exercicio_03_acesso_seguro.dart
Exercício 4
Verifica cidade != null em um if e, dentro do bloco, o Dart promove cidade de String? para String automaticamente — dispensando ?. ou ! para chamar toUpperCase().
// Demonstração de promoção de tipo (type promotion) em Dart.
// Quando verificamos que uma variável nullable não é null com 'if (x != null)',
// o Dart automaticamente trata a variável como não-nullable dentro do bloco if.
// Isso elimina a necessidade de usar '?.' ou '!' após a verificação.
void main() {
// 'cidade' pode ser null — tipo String?.
String? cidade = buscarCidade();
// Dentro do bloco if, após verificar 'cidade != null',
// o Dart promove 'cidade' para String (não-nullable).
// Portanto, podemos chamar toUpperCase() diretamente sem '?.'.
if (cidade != null) {
print('Cidade: ${cidade.toUpperCase()}');
} else {
print('Cidade nao informada');
}
}
// Retorna uma cidade como String, mas poderia retornar null em outro contexto.
String? buscarCidade() {
return 'Curitiba';
}
Saída esperada
Cidade: CURITIBA
Como executar
dart run 22-Nullability_Safety/02_Exercicios/codigo_fonte/exercicio_04_promocao_tipo.dart
Exercício 5
Mostra um caso seguro do operador !: só é usado depois de verificar if (dados['nome'] != null), convertendo String? em String naquele ponto para chamar toUpperCase().
// Demonstração do operador bang '!' (non-null assertion) em Dart.
// O operador '!' afirma ao compilador que o valor NÃO é null naquele ponto.
// ATENÇÃO: se o valor for null em runtime, lança NullReferenceError.
// Use '!' apenas quando tiver certeza absoluta de que o valor não é null.
void main() {
// Map com uma chave 'nome' que tem valor String não-null.
Map<String, String?> dados = {'nome': 'Ana'};
// dados['nome'] retorna String? (pode ser null se a chave não existir).
// Verificamos com 'if (dados['nome'] != null)' antes de usar '!'.
if (dados['nome'] != null) {
// '!' converte String? para String dentro do bloco (garantido não ser null).
// Sem '!', o compilador recusaria chamar toUpperCase() em String?.
print(dados['nome']!.toUpperCase());
}
}
Saída esperada
ANA
Como executar
dart run 22-Nullability_Safety/02_Exercicios/codigo_fonte/exercicio_05_operador_bang.dart
Exercício 6
Cria a classe Configuracao com o campo late String ambiente, inicializado fora do construtor pelo método inicializar(). Demonstra como adiar a inicialização de um campo não-nullable até um momento posterior garantido.
// Demonstração da palavra-chave 'late' em Dart.
// 'late' indica que uma variável não-nullable será inicializada
// antes do primeiro uso — mas não necessariamente no construtor.
// Evita ter que usar null para variáveis que serão inicializadas depois.
class Configuracao {
// 'late' adia a inicialização de 'ambiente' para um momento posterior.
// Sem 'late', o Dart exigiria valor inicial ou permitir null (String?).
// Se 'ambiente' for acessado antes de ser inicializado, lança LateInitializationError.
late String ambiente;
// Método que inicializa 'ambiente' após a criação do objeto.
void inicializar() {
ambiente = 'desenvolvimento';
}
}
void main() {
Configuracao configuracao = Configuracao();
// Inicializa 'ambiente' antes de acessá-lo — necessário com 'late'.
configuracao.inicializar();
// Acessa 'ambiente' com segurança: já foi inicializado pelo método inicializar().
print('Ambiente: ${configuracao.ambiente}');
}
Saída esperada
Ambiente: desenvolvimento
Como executar
dart run 22-Nullability_Safety/02_Exercicios/codigo_fonte/exercicio_06_late.dart