Projeto Agenda de Contatos
Uma agenda que cadastra, lista, busca e remove contatos e, o mais importante, lembra deles: tudo fica gravado num arquivo de texto e volta na próxima vez que o programa abrir. É o primeiro projeto do guia que guarda dados de verdade, e por isso o primeiro em que você vai cuidar de arquivos que podem estar faltando ou estragados.
- Representar um contato com um record.
- Guardar vários contatos numa lista (ArrayList).
- Montar um menu com switch com setas e ler linhas inteiras com
nextLine. - Buscar com métodos de String (
toLowerCase,contains) e remover com segurança. - Salvar e carregar com
FilesePath(Ler e Escrever Arquivos), tratandoIOExceptioncom try e catch.
O que vamos construir
A agenda pronta. Ela já tinha quatro contatos salvos de outras vezes; a Ana lista, busca, remove um, adiciona outro e sai. Depois, o cat mostra o arquivo que a agenda gravou:
$ java Agenda.java === Agenda da Ana === 4 contato(s) carregado(s) 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 1 1. Bruno Lima | (11) 91234-5678 | bruno@exemplo.com 2. Carla Dias | (21) 99876-5432 | carla@exemplo.com 3. Diego Rocha | (31) 98888-1111 | diego@exemplo.com 4. Elisa Prado | (41) 95555-3333 | 4 contato(s). 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 3 Buscar por: car - Carla Dias | (21) 99876-5432 | carla@exemplo.com 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 4 Nome para remover: Diego Rocha Removido: Diego Rocha 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 2 Nome: Fábio Nunes Telefone: (51) 94444-7777 E-mail: fabio@exemplo.com Adicionado: Fábio Nunes 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 1 1. Bruno Lima | (11) 91234-5678 | bruno@exemplo.com 2. Carla Dias | (21) 99876-5432 | carla@exemplo.com 3. Elisa Prado | (41) 95555-3333 | 4. Fábio Nunes | (51) 94444-7777 | fabio@exemplo.com 4 contato(s). 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 0 Até logo! $ cat contatos.txt Bruno Lima;(11) 91234-5678;bruno@exemplo.com Carla Dias;(21) 99876-5432;carla@exemplo.com Elisa Prado;(41) 95555-3333; Fábio Nunes;(51) 94444-7777;fabio@exemplo.com
- O contato (
record). - A lista de contatos (
ArrayList, listar). - O menu e o cadastro (
Scanner.nextLine,switch). - Buscar e remover (
contains,remove). - Salvar no arquivo (
Files.write,IOException). - Carregar ao abrir (
Files.readAllLines,split).
Antes de começar
Você vai usar o que viu nos projetos anteriores (menu com laço, métodos) e precisa conhecer Records e o básico de ArrayList. No seu computador:
$ mkdir -p java/agenda $ cd java/agenda
Etapa 1 · O contato
Um contato tem nome, telefone e e-mail: três textos que andam sempre juntos. Em vez de três variáveis soltas, criamos um tipo novo, Contato, com um record ("registro"): uma classe feita só para carregar dados, escrita numa linha.
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
Contato bruno = new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com");
Contato carla = new Contato("Carla Dias", "(21) 99876-5432", "carla@exemplo.com");
System.out.println(bruno);
System.out.println(carla.nome() + " - " + carla.telefone());
}
}
- record Contato(…)
- Declara o tipo
Contato. Ele fica dentro da classeAgenda(um record "aninhado"), como o enum do jogo. - String nome, String telefone, String email
- Os componentes: os dados que todo contato carrega.
- { }
- O corpo, vazio por enquanto. Na etapa 5 vamos colocar um método aqui.
Só com essa linha, o Java cria sozinho tudo isto:
| O record ganha | Exemplo | Resultado |
|---|---|---|
| Um construtor com os três componentes | new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com") | Um contato novo |
| Um método para ler cada componente | carla.nome() | "Carla Dias" |
Um toString legível | System.out.println(bruno) | Contato[nome=…, telefone=…, email=…] |
equals e hashCode | a.equals(b) | true se os três componentes forem iguais |
$ java Agenda.java Contato[nome=Bruno Lima, telefone=(11) 91234-5678, email=bruno@exemplo.com] Carla Dias - (21) 99876-5432
Repare: para ler o nome, é carla.nome(), com parênteses. Não é getNome() como nas classes comuns (get e set), e não é carla.nome sem parênteses.
Este código tem um erro de propósito.
Contato bruno = new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com");
bruno.telefone = "(11) 90000-0000";
$ java Agenda.java
Agenda.java:8: error: cannot assign a value to final variable telefone
bruno.telefone = "(11) 90000-0000";
^
1 error
error: compilation failed
"Não dá para atribuir um valor à variável final telefone." Os componentes de um record são final: um contato, depois de criado, não muda (ele é imutável). Para "trocar o telefone", crie um contato novo com o telefone novo e coloque-o no lugar do antigo. A última linha, error: compilation failed, é do lançador java: no modo arquivo-fonte, ele compila antes de rodar e avisa que a compilação falhou.
Missão (etapa 1): crie o contato carla (Carla Dias, (21) 99876-5432, carla@exemplo.com) e mostre Carla Dias - (21) 99876-5432 usando carla.nome() e carla.telefone().
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
Contato bruno = new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com");
System.out.println(bruno);
// crie a Carla e mostre o nome e o telefone dela
}
}
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
Contato bruno = new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com");
Contato carla = new Contato("Carla Dias", "(21) 99876-5432", "carla@exemplo.com");
System.out.println(bruno);
System.out.println(carla.nome() + " - " + carla.telefone());
}
}
Etapa 2 · A lista de contatos
Uma agenda tem muitos contatos, e não sabemos quantos. Um array tem tamanho fixo; uma lista (ArrayList) cresce sozinha a cada add. Criamos também o método listar, que mostra os contatos numerados.
import java.util.ArrayList;
import java.util.List;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
List<Contato> contatos = new ArrayList<>();
contatos.add(new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com"));
contatos.add(new Contato("Carla Dias", "(21) 99876-5432", "carla@exemplo.com"));
contatos.add(new Contato("Diego Rocha", "(31) 98888-1111", "diego@exemplo.com"));
listar(contatos);
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
}
| Trecho | O que faz |
|---|---|
List<Contato> contatos | Uma lista que só aceita Contato. O <Contato> é o "tipo dos itens" (generics). Declaramos como List (a interface) e criamos um ArrayList (a implementação). |
new ArrayList<>() | Lista vazia. O <> vazio ("diamante") repete o tipo da esquerda. |
contatos.add(…) | Põe um contato no fim da lista. |
contatos.isEmpty() | true se a lista não tem nada. |
contatos.size() e contatos.get(i) | Quantos itens há, e o item da posição i (começando em 0). Por isso mostramos i + 1. |
$ java Agenda.java 1. Bruno Lima | (11) 91234-5678 | bruno@exemplo.com 2. Carla Dias | (21) 99876-5432 | carla@exemplo.com 3. Diego Rocha | (31) 98888-1111 | diego@exemplo.com 3 contato(s).
Missão (etapa 2): escreva o corpo do método listar: um for que mostra cada contato no formato 1. Nome | telefone | email e, no fim, 3 contato(s). Se a lista estiver vazia, mostre Nenhum contato.
import java.util.ArrayList;
import java.util.List;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
List<Contato> contatos = new ArrayList<>();
contatos.add(new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com"));
contatos.add(new Contato("Carla Dias", "(21) 99876-5432", "carla@exemplo.com"));
contatos.add(new Contato("Diego Rocha", "(31) 98888-1111", "diego@exemplo.com"));
listar(contatos);
}
static void listar(List<Contato> contatos) {
// mostre cada contato numerado e, no fim, o total
}
}
import java.util.ArrayList;
import java.util.List;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
List<Contato> contatos = new ArrayList<>();
contatos.add(new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com"));
contatos.add(new Contato("Carla Dias", "(21) 99876-5432", "carla@exemplo.com"));
contatos.add(new Contato("Diego Rocha", "(31) 98888-1111", "diego@exemplo.com"));
listar(contatos);
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
}
Etapa 3 · O menu e o cadastro
Agora a lista começa vazia e quem cadastra é a pessoa, por um menu. O formato é o mesmo da calculadora (while (true) + switch), com uma diferença importante: aqui lemos linhas inteiras com nextLine(), porque nomes têm espaço.
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
List<Contato> contatos = new ArrayList<>();
System.out.println("=== Agenda da Ana ===");
while (true) {
System.out.println();
System.out.println("1) Listar 2) Adicionar 0) Sair");
System.out.print("Opção: ");
String opcao = entrada.nextLine().trim();
switch (opcao) {
case "1" -> listar(contatos);
case "2" -> adicionar(entrada, contatos);
case "0" -> {
System.out.println("Até logo!");
return;
}
default -> System.out.println("Opção inválida: " + opcao);
}
}
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
static void adicionar(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome: ");
String nome = entrada.nextLine().trim();
if (nome.isEmpty()) {
System.out.println("O nome não pode ficar vazio.");
return;
}
System.out.print("Telefone: ");
String telefone = entrada.nextLine().trim();
System.out.print("E-mail: ");
String email = entrada.nextLine().trim();
contatos.add(new Contato(nome, telefone, email));
System.out.println("Adicionado: " + nome);
}
}
- entrada.nextLine()
- Lê tudo até o Enter, com espaços:
Bruno Limainteiro. Onext()leria sóBruno. - .trim()
- Corta espaços do começo e do fim (quem nunca digitou um espaço a mais?).
- switch (opcao) { case "1" -> …; }
- Aqui o switch é uma instrução (não devolve valor): cada seta só chama um método. A opção é lida como texto, então "abc" cai no
defaultsem exceção nenhuma. - case "0" -> { …; return; }
- Duas instruções, então vão entre chaves. O
returnsai domaine encerra o programa. - if (nome.isEmpty())
- Recusa nome vazio: quem aperta Enter sem digitar não cria um contato "fantasma".
$ java Agenda.java === Agenda da Ana === 1) Listar 2) Adicionar 0) Sair Opção: 1 Nenhum contato. 1) Listar 2) Adicionar 0) Sair Opção: 2 Nome: Bruno Lima Telefone: (11) 91234-5678 E-mail: bruno@exemplo.com Adicionado: Bruno Lima 1) Listar 2) Adicionar 0) Sair Opção: 2 Nome: « a Ana só apertou Enter O nome não pode ficar vazio. 1) Listar 2) Adicionar 0) Sair Opção: 7 Opção inválida: 7 1) Listar 2) Adicionar 0) Sair Opção: 1 1. Bruno Lima | (11) 91234-5678 | bruno@exemplo.com 1 contato(s). 1) Listar 2) Adicionar 0) Sair Opção: 0 Até logo!
nextInt() para a opção?
Misturar nextInt() com nextLine() é a armadilha mais famosa do Scanner: o nextInt() lê o número, mas deixa o Enter na entrada, e o nextLine() seguinte lê essa "linha vazia" na hora, pulando a pergunta do nome. Lendo tudo com nextLine(), o problema não existe. Veja a explicação completa em Ler do Teclado (Scanner).
Missão (etapa 3): o menu já mostra a opção 2, mas ela ainda não faz nada. Acrescente o case "2" e escreva o método adicionar: pergunte Nome: , Telefone: e E-mail: com nextLine(), recuse nome vazio, adicione na lista e mostre Adicionado: Bruno Lima.
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
List<Contato> contatos = new ArrayList<>();
System.out.println("=== Agenda da Ana ===");
while (true) {
System.out.println();
System.out.println("1) Listar 2) Adicionar 0) Sair");
System.out.print("Opção: ");
String opcao = entrada.nextLine().trim();
switch (opcao) {
case "1" -> listar(contatos);
case "0" -> {
System.out.println("Até logo!");
return;
}
default -> System.out.println("Opção inválida: " + opcao);
}
}
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
static void adicionar(Scanner entrada, List<Contato> contatos) {
// pergunte nome, telefone e e-mail com nextLine(),
// recuse nome vazio e adicione o contato na lista
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
List<Contato> contatos = new ArrayList<>();
System.out.println("=== Agenda da Ana ===");
while (true) {
System.out.println();
System.out.println("1) Listar 2) Adicionar 0) Sair");
System.out.print("Opção: ");
String opcao = entrada.nextLine().trim();
switch (opcao) {
case "1" -> listar(contatos);
case "2" -> adicionar(entrada, contatos);
case "0" -> {
System.out.println("Até logo!");
return;
}
default -> System.out.println("Opção inválida: " + opcao);
}
}
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
static void adicionar(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome: ");
String nome = entrada.nextLine().trim();
if (nome.isEmpty()) {
System.out.println("O nome não pode ficar vazio.");
return;
}
System.out.print("Telefone: ");
String telefone = entrada.nextLine().trim();
System.out.print("E-mail: ");
String email = entrada.nextLine().trim();
contatos.add(new Contato(nome, telefone, email));
System.out.println("Adicionado: " + nome);
}
}
Etapa 4 · Buscar e remover
Duas opções novas no menu: 3) Buscar e 4) Remover. A busca encontra contatos por parte do nome, sem ligar para maiúsculas; a remoção apaga pelo nome completo.
static void buscar(Scanner entrada, List<Contato> contatos) {
System.out.print("Buscar por: ");
String termo = entrada.nextLine().trim().toLowerCase();
int achados = 0;
for (Contato c : contatos) {
if (c.nome().toLowerCase().contains(termo)) {
System.out.println("- " + c.nome() + " | " + c.telefone() + " | " + c.email());
achados++;
}
}
if (achados == 0) {
System.out.println("Nenhum contato com \"" + termo + "\".");
}
}
static void remover(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome para remover: ");
String nome = entrada.nextLine().trim();
for (Contato c : contatos) {
if (c.nome().equalsIgnoreCase(nome)) {
contatos.remove(c);
System.out.println("Removido: " + c.nome());
return;
}
}
System.out.println("Não encontrei \"" + nome + "\".");
}
| Trecho | O que faz |
|---|---|
termo.toLowerCase() e c.nome().toLowerCase() | Passa os dois lados para minúsculas, para que "carl" ache "Carla". Comparar só um lado não funcionaria. |
.contains(termo) | true se o termo aparece em qualquer lugar do nome. |
for (Contato c : contatos) | O for-each: "para cada contato c da lista". Não precisa de índice. |
equalsIgnoreCase(nome) | Igualdade exata, ignorando maiúsculas: "bruno lima" remove "Bruno Lima". |
contatos.remove(c) seguido de return | Tira o contato da lista e sai do método na hora. O return é obrigatório aqui; veja o cenário abaixo. |
$ java Agenda.java === Agenda da Ana === … « a Ana cadastrou Bruno, Carla e Carlos 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 3 Buscar por: carl - Carla Dias | (21) 99876-5432 | carla@exemplo.com - Carlos Mendes | (11) 97777-2222 | carlos@exemplo.com 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 3 Buscar por: zé Nenhum contato com "zé". 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 4 Nome para remover: bruno lima Removido: Bruno Lima 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 4 Nome para remover: Bruno Lima Não encontrei "Bruno Lima". « já tinha sido removido 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 1 1. Carla Dias | (21) 99876-5432 | carla@exemplo.com 2. Carlos Mendes | (11) 97777-2222 | carlos@exemplo.com 2 contato(s).
A Ana quis remover todos os contatos que começam com "Carl" e tirou o return:
Este código tem um erro de propósito.
for (Contato c : contatos) {
if (c.nome().startsWith("Carl")) {
contatos.remove(c);
}
}
$ java Agenda.java Exception in thread "main" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1096) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1050) at Agenda.main(Agenda.java:15)
"Modificação concorrente": a lista mudou enquanto o for-each andava por ela, e o Java parou tudo para não pular ou repetir itens. Com o return logo depois do remove, o laço nunca dá o próximo passo, e por isso a etapa 4 funciona. Para remover vários de uma vez, use contatos.removeIf(c -> c.nome().startsWith("Carl")) (com uma lambda) ou um Iterator.
Missão (etapa 4): complete o método buscar. A entrada da missão cadastra Carla e Carlos e busca carl (deve achar os dois) e zé (deve mostrar Nenhum contato com "zé".).
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
List<Contato> contatos = new ArrayList<>();
System.out.println("=== Agenda da Ana ===");
while (true) {
System.out.println();
System.out.println("1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair");
System.out.print("Opção: ");
String opcao = entrada.nextLine().trim();
switch (opcao) {
case "1" -> listar(contatos);
case "2" -> adicionar(entrada, contatos);
case "3" -> buscar(entrada, contatos);
case "4" -> remover(entrada, contatos);
case "0" -> {
System.out.println("Até logo!");
return;
}
default -> System.out.println("Opção inválida: " + opcao);
}
}
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
static void adicionar(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome: ");
String nome = entrada.nextLine().trim();
if (nome.isEmpty()) {
System.out.println("O nome não pode ficar vazio.");
return;
}
System.out.print("Telefone: ");
String telefone = entrada.nextLine().trim();
System.out.print("E-mail: ");
String email = entrada.nextLine().trim();
contatos.add(new Contato(nome, telefone, email));
System.out.println("Adicionado: " + nome);
}
static void buscar(Scanner entrada, List<Contato> contatos) {
System.out.print("Buscar por: ");
String termo = entrada.nextLine().trim().toLowerCase();
// mostre os contatos cujo nome contém o termo (sem diferenciar maiúsculas)
// e avise se nenhum foi encontrado
}
static void remover(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome para remover: ");
String nome = entrada.nextLine().trim();
for (Contato c : contatos) {
if (c.nome().equalsIgnoreCase(nome)) {
contatos.remove(c);
System.out.println("Removido: " + c.nome());
return;
}
}
System.out.println("Não encontrei \"" + nome + "\".");
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
List<Contato> contatos = new ArrayList<>();
System.out.println("=== Agenda da Ana ===");
while (true) {
System.out.println();
System.out.println("1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair");
System.out.print("Opção: ");
String opcao = entrada.nextLine().trim();
switch (opcao) {
case "1" -> listar(contatos);
case "2" -> adicionar(entrada, contatos);
case "3" -> buscar(entrada, contatos);
case "4" -> remover(entrada, contatos);
case "0" -> {
System.out.println("Até logo!");
return;
}
default -> System.out.println("Opção inválida: " + opcao);
}
}
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
static void adicionar(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome: ");
String nome = entrada.nextLine().trim();
if (nome.isEmpty()) {
System.out.println("O nome não pode ficar vazio.");
return;
}
System.out.print("Telefone: ");
String telefone = entrada.nextLine().trim();
System.out.print("E-mail: ");
String email = entrada.nextLine().trim();
contatos.add(new Contato(nome, telefone, email));
System.out.println("Adicionado: " + nome);
}
static void buscar(Scanner entrada, List<Contato> contatos) {
System.out.print("Buscar por: ");
String termo = entrada.nextLine().trim().toLowerCase();
int achados = 0;
for (Contato c : contatos) {
if (c.nome().toLowerCase().contains(termo)) {
System.out.println("- " + c.nome() + " | " + c.telefone() + " | " + c.email());
achados++;
}
}
if (achados == 0) {
System.out.println("Nenhum contato com \"" + termo + "\".");
}
}
static void remover(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome para remover: ");
String nome = entrada.nextLine().trim();
for (Contato c : contatos) {
if (c.nome().equalsIgnoreCase(nome)) {
contatos.remove(c);
System.out.println("Removido: " + c.nome());
return;
}
}
System.out.println("Não encontrei \"" + nome + "\".");
}
}
Etapa 5 · Salvar no arquivo
Até aqui, fechar o programa apaga tudo: a lista mora na memória. Para guardar, vamos gravar cada contato como uma linha de um arquivo de texto, com os campos separados por ;:
Bruno Lima;(11) 91234-5678;bruno@exemplo.com Carla Dias;(21) 99876-5432;carla@exemplo.com
Três mudanças no código. Primeiro, o record aprende a se transformar numa linha, e o caminho do arquivo vira uma constante:
record Contato(String nome, String telefone, String email) {
String paraLinha() {
return nome + ";" + telefone + ";" + email;
}
}
static final Path ARQUIVO = Path.of("contatos.txt");
Segundo, o método que grava:
static void salvar(List<Contato> contatos) {
List<String> linhas = new ArrayList<>();
for (Contato c : contatos) {
linhas.add(c.paraLinha());
}
try {
Files.write(ARQUIVO, linhas);
} catch (IOException e) {
System.out.println("Erro ao salvar: " + e);
}
}
Terceiro, salvar(contatos); é chamado logo depois de cada add (em adicionar) e de cada remove (em remover). Assim o arquivo está sempre em dia, mesmo se o programa for fechado de repente. E no topo do arquivo entram três import: java.io.IOException, java.nio.file.Files e java.nio.file.Path.
| Trecho | O que faz |
|---|---|
String paraLinha() dentro do record | Um record pode ter métodos. Dentro dele, nome é o componente do próprio contato. |
Path.of("contatos.txt") | Um caminho de arquivo. Sem pasta na frente, é relativo à pasta onde você rodou o java. |
Files.write(ARQUIVO, linhas) | Grava cada String da lista como uma linha. Cria o arquivo se não existir e substitui o conteúdo se existir. |
try { … } catch (IOException e) { … } | Gravar pode falhar (disco cheio, pasta sem permissão). Se falhar, mostramos o erro em vez de derrubar o programa. |
$ java Agenda.java === Agenda da Ana === 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 2 Nome: Bruno Lima Telefone: (11) 91234-5678 E-mail: bruno@exemplo.com Adicionado: Bruno Lima 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 2 Nome: Carla Dias Telefone: (21) 99876-5432 E-mail: carla@exemplo.com Adicionado: Carla Dias 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 0 Até logo! $ ls Agenda.java contatos.txt « o arquivo apareceu $ cat contatos.txt Bruno Lima;(11) 91234-5678;bruno@exemplo.com Carla Dias;(21) 99876-5432;carla@exemplo.com
Este código tem um erro de propósito.
Files.write(ARQUIVO, linhas);
$ java Agenda.java
Agenda.java:104: error: unreported exception IOException; must be caught or declared to be thrown
Files.write(ARQUIVO, linhas);
^
1 error
error: compilation failed
"Exceção IOException não informada; precisa ser capturada ou declarada." IOException é uma exceção checked: o compilador obriga você a decidir o que fazer com ela, com try/catch ou com throws IOException na assinatura do método. Veja Checked × Unchecked.
Missão (etapa 5): este programa menor salva dois contatos e depois mostra o arquivo com Files.readString. Rode antes: dá NoSuchFileException, porque salvar ainda não grava nada. Escreva o salvar com paraLinha(), Files.write e try/catch.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class Agenda {
record Contato(String nome, String telefone, String email) {
String paraLinha() {
return nome + ";" + telefone + ";" + email;
}
}
static final Path ARQUIVO = Path.of("contatos.txt");
public static void main(String[] args) throws IOException {
List<Contato> contatos = new ArrayList<>();
contatos.add(new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com"));
contatos.add(new Contato("Carla Dias", "(21) 99876-5432", "carla@exemplo.com"));
salvar(contatos);
System.out.print(Files.readString(ARQUIVO));
}
static void salvar(List<Contato> contatos) {
// transforme cada contato numa linha e grave com Files.write
}
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class Agenda {
record Contato(String nome, String telefone, String email) {
String paraLinha() {
return nome + ";" + telefone + ";" + email;
}
}
static final Path ARQUIVO = Path.of("contatos.txt");
public static void main(String[] args) throws IOException {
List<Contato> contatos = new ArrayList<>();
contatos.add(new Contato("Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com"));
contatos.add(new Contato("Carla Dias", "(21) 99876-5432", "carla@exemplo.com"));
salvar(contatos);
System.out.print(Files.readString(ARQUIVO));
}
static void salvar(List<Contato> contatos) {
List<String> linhas = new ArrayList<>();
for (Contato c : contatos) {
linhas.add(c.paraLinha());
}
try {
Files.write(ARQUIVO, linhas);
} catch (IOException e) {
System.out.println("Erro ao salvar: " + e);
}
}
}
Etapa 6 · Carregar ao abrir
Falta o caminho de volta: ao abrir, ler o arquivo e recriar os contatos. Cada linha é cortada nos ; com split, e os pedaços viram um Contato. O main passa a começar com List<Contato> contatos = carregar(); e mostra quantos vieram. A primeira versão, ingênua:
static List<Contato> carregar() {
List<Contato> contatos = new ArrayList<>();
if (!Files.exists(ARQUIVO)) {
return contatos;
}
try {
for (String linha : Files.readAllLines(ARQUIVO)) {
String[] partes = linha.split(";");
contatos.add(new Contato(partes[0], partes[1], partes[2]));
}
} catch (IOException e) {
System.out.println("Erro ao carregar: " + e);
}
return contatos;
}
- Files.exists(ARQUIVO)
- Na primeira vez, o arquivo ainda não existe. Sem essa conferência,
readAllLineslançariaNoSuchFileException. - Files.readAllLines(ARQUIVO)
- Lê o arquivo inteiro e devolve uma
List<String>, uma linha por item. - linha.split(";")
- Corta o texto em cada
;e devolve um array:["Bruno Lima", "(11) 91234-5678", "bruno@exemplo.com"]. - partes[0], partes[1], partes[2]
- Nome, telefone e e-mail, nas posições 0, 1 e 2.
Funciona… até a Ana cadastrar alguém sem e-mail:
$ java Agenda.java === Agenda da Ana === 3 contato(s) carregado(s) 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 2 Nome: Elisa Prado Telefone: (41) 95555-3333 E-mail: « a Ana não sabia o e-mail e apertou Enter Adicionado: Elisa Prado 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 0 Até logo! $ cat contatos.txt Bruno Lima;(11) 91234-5678;bruno@exemplo.com Carla Dias;(21) 99876-5432;carla@exemplo.com Diego Rocha;(31) 98888-1111;diego@exemplo.com Elisa Prado;(41) 95555-3333; $ java Agenda.java Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 2 out of bounds for length 2 at Agenda.carregar(Agenda.java:119) at Agenda.main(Agenda.java:20)
A agenda não abre mais! "Índice 2 fora dos limites para tamanho 2": o array partes tem só 2 itens e o código pediu o terceiro. O culpado é um detalhe do split: ele descarta os pedaços vazios do fim. "Elisa Prado;(41) 95555-3333;" vira só dois pedaços. A versão corrigida:
for (String linha : Files.readAllLines(ARQUIVO)) {
String[] partes = linha.split(";", -1);
if (partes.length == 3) {
contatos.add(new Contato(partes[0], partes[1], partes[2]));
} else if (!linha.isBlank()) {
System.out.println("Linha ignorada: " + linha);
}
}
| Correção | O que resolve |
|---|---|
split(";", -1) | O -1 manda o split manter os pedaços vazios do fim: a Elisa volta com e-mail "". |
if (partes.length == 3) | Só cria o contato se a linha tiver exatamente três campos. |
else if (!linha.isBlank()) | Linha estragada (e não vazia): avisa e segue em frente, em vez de derrubar a agenda inteira. |
$ echo "linha estragada" >> contatos.txt « a Ana estraga o arquivo de propósito $ java Agenda.java Linha ignorada: linha estragada === Agenda da Ana === 4 contato(s) carregado(s) 1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair Opção: 0 Até logo!
Nunca confie que o arquivo está perfeito. Ele pode não existir, estar vazio, ter sido editado à mão ou gravado por uma versão antiga do programa. Confira antes de usar: Files.exists, o tamanho do array, isBlank.
Missão (etapa 6): este programa grava um arquivo com três linhas (uma sem e-mail e uma estragada) e chama carregar. Rode: dá ArrayIndexOutOfBoundsException. Conserte o carregar com split(";", -1) e a conferência do tamanho, para carregar 2 contatos e mostrar Linha ignorada: linha estragada.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
static final Path ARQUIVO = Path.of("contatos.txt");
public static void main(String[] args) throws IOException {
Files.writeString(ARQUIVO, """
Bruno Lima;(11) 91234-5678;bruno@exemplo.com
Elisa Prado;(41) 95555-3333;
linha estragada
""");
List<Contato> contatos = carregar();
System.out.println(contatos.size() + " contato(s) carregado(s)");
System.out.println(contatos);
}
static List<Contato> carregar() {
List<Contato> contatos = new ArrayList<>();
try {
for (String linha : Files.readAllLines(ARQUIVO)) {
String[] partes = linha.split(";");
contatos.add(new Contato(partes[0], partes[1], partes[2]));
}
} catch (IOException e) {
System.out.println("Erro ao carregar: " + e);
}
return contatos;
}
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class Agenda {
record Contato(String nome, String telefone, String email) {
}
static final Path ARQUIVO = Path.of("contatos.txt");
public static void main(String[] args) throws IOException {
Files.writeString(ARQUIVO, """
Bruno Lima;(11) 91234-5678;bruno@exemplo.com
Elisa Prado;(41) 95555-3333;
linha estragada
""");
List<Contato> contatos = carregar();
System.out.println(contatos.size() + " contato(s) carregado(s)");
System.out.println(contatos);
}
static List<Contato> carregar() {
List<Contato> contatos = new ArrayList<>();
try {
for (String linha : Files.readAllLines(ARQUIVO)) {
String[] partes = linha.split(";", -1);
if (partes.length == 3) {
contatos.add(new Contato(partes[0], partes[1], partes[2]));
} else if (!linha.isBlank()) {
System.out.println("Linha ignorada: " + linha);
}
}
} catch (IOException e) {
System.out.println("Erro ao carregar: " + e);
}
return contatos;
}
}
O código completo
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Agenda {
record Contato(String nome, String telefone, String email) {
String paraLinha() {
return nome + ";" + telefone + ";" + email;
}
}
static final Path ARQUIVO = Path.of("contatos.txt");
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
List<Contato> contatos = carregar();
System.out.println("=== Agenda da Ana === " + contatos.size() + " contato(s) carregado(s)");
while (true) {
System.out.println();
System.out.println("1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair");
System.out.print("Opção: ");
String opcao = entrada.nextLine().trim();
switch (opcao) {
case "1" -> listar(contatos);
case "2" -> adicionar(entrada, contatos);
case "3" -> buscar(entrada, contatos);
case "4" -> remover(entrada, contatos);
case "0" -> {
System.out.println("Até logo!");
return;
}
default -> System.out.println("Opção inválida: " + opcao);
}
}
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
static void adicionar(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome: ");
String nome = entrada.nextLine().trim();
if (nome.isEmpty()) {
System.out.println("O nome não pode ficar vazio.");
return;
}
System.out.print("Telefone: ");
String telefone = entrada.nextLine().trim();
System.out.print("E-mail: ");
String email = entrada.nextLine().trim();
contatos.add(new Contato(nome, telefone, email));
salvar(contatos);
System.out.println("Adicionado: " + nome);
}
static void buscar(Scanner entrada, List<Contato> contatos) {
System.out.print("Buscar por: ");
String termo = entrada.nextLine().trim().toLowerCase();
int achados = 0;
for (Contato c : contatos) {
if (c.nome().toLowerCase().contains(termo)) {
System.out.println("- " + c.nome() + " | " + c.telefone() + " | " + c.email());
achados++;
}
}
if (achados == 0) {
System.out.println("Nenhum contato com \"" + termo + "\".");
}
}
static void remover(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome para remover: ");
String nome = entrada.nextLine().trim();
for (Contato c : contatos) {
if (c.nome().equalsIgnoreCase(nome)) {
contatos.remove(c);
salvar(contatos);
System.out.println("Removido: " + c.nome());
return;
}
}
System.out.println("Não encontrei \"" + nome + "\".");
}
static void salvar(List<Contato> contatos) {
List<String> linhas = new ArrayList<>();
for (Contato c : contatos) {
linhas.add(c.paraLinha());
}
try {
Files.write(ARQUIVO, linhas);
} catch (IOException e) {
System.out.println("Erro ao salvar: " + e);
}
}
static List<Contato> carregar() {
List<Contato> contatos = new ArrayList<>();
if (!Files.exists(ARQUIVO)) {
return contatos;
}
try {
for (String linha : Files.readAllLines(ARQUIVO)) {
String[] partes = linha.split(";", -1);
if (partes.length == 3) {
contatos.add(new Contato(partes[0], partes[1], partes[2]));
} else if (!linha.isBlank()) {
System.out.println("Linha ignorada: " + linha);
}
}
} catch (IOException e) {
System.out.println("Erro ao carregar: " + e);
}
return contatos;
}
}
Em programas maiores, cada tipo vai no seu arquivo: Contato.java com public record Contato(…) { … }, e Agenda.java com o resto. Desde o Java 22, java Agenda.java encontra sozinho o Contato.java na mesma pasta. O próximo projeto é organizado assim.
Desafios extras
- Sem nomes repetidos. Em
adicionar, recuse um nome que já existe (ignorando maiúsculas). - Lista em ordem alfabética. Antes de listar, ordene:
contatos.sort(Comparator.comparing(Contato::nome))(veja Comparable e Comparator). - Editar o telefone. Uma opção 5 que troca o telefone. Como o record é imutável, use
contatos.set(i, new Contato(…))na posiçãoi. - O
;dentro do nome. O que acontece se alguém cadastrarAna; a melhor? Recuse nomes com;ou troque o separador. - Buscar também pelo telefone. Faça a busca olhar nome ou telefone.
Desafio 1 no editor: em adicionar, logo depois de conferir o nome vazio, percorra a lista e, se já houver um contato com o mesmo nome (ignorando maiúsculas), mostre Já existe um contato chamado Bruno Lima. e não adicione.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Agenda {
record Contato(String nome, String telefone, String email) {
String paraLinha() {
return nome + ";" + telefone + ";" + email;
}
}
static final Path ARQUIVO = Path.of("contatos.txt");
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
List<Contato> contatos = carregar();
System.out.println("=== Agenda da Ana === " + contatos.size() + " contato(s) carregado(s)");
while (true) {
System.out.println();
System.out.println("1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair");
System.out.print("Opção: ");
String opcao = entrada.nextLine().trim();
switch (opcao) {
case "1" -> listar(contatos);
case "2" -> adicionar(entrada, contatos);
case "3" -> buscar(entrada, contatos);
case "4" -> remover(entrada, contatos);
case "0" -> {
System.out.println("Até logo!");
return;
}
default -> System.out.println("Opção inválida: " + opcao);
}
}
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
static void adicionar(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome: ");
String nome = entrada.nextLine().trim();
if (nome.isEmpty()) {
System.out.println("O nome não pode ficar vazio.");
return;
}
System.out.print("Telefone: ");
String telefone = entrada.nextLine().trim();
System.out.print("E-mail: ");
String email = entrada.nextLine().trim();
contatos.add(new Contato(nome, telefone, email));
salvar(contatos);
System.out.println("Adicionado: " + nome);
}
static void buscar(Scanner entrada, List<Contato> contatos) {
System.out.print("Buscar por: ");
String termo = entrada.nextLine().trim().toLowerCase();
int achados = 0;
for (Contato c : contatos) {
if (c.nome().toLowerCase().contains(termo)) {
System.out.println("- " + c.nome() + " | " + c.telefone() + " | " + c.email());
achados++;
}
}
if (achados == 0) {
System.out.println("Nenhum contato com \"" + termo + "\".");
}
}
static void remover(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome para remover: ");
String nome = entrada.nextLine().trim();
for (Contato c : contatos) {
if (c.nome().equalsIgnoreCase(nome)) {
contatos.remove(c);
salvar(contatos);
System.out.println("Removido: " + c.nome());
return;
}
}
System.out.println("Não encontrei \"" + nome + "\".");
}
static void salvar(List<Contato> contatos) {
List<String> linhas = new ArrayList<>();
for (Contato c : contatos) {
linhas.add(c.paraLinha());
}
try {
Files.write(ARQUIVO, linhas);
} catch (IOException e) {
System.out.println("Erro ao salvar: " + e);
}
}
static List<Contato> carregar() {
List<Contato> contatos = new ArrayList<>();
if (!Files.exists(ARQUIVO)) {
return contatos;
}
try {
for (String linha : Files.readAllLines(ARQUIVO)) {
String[] partes = linha.split(";", -1);
if (partes.length == 3) {
contatos.add(new Contato(partes[0], partes[1], partes[2]));
} else if (!linha.isBlank()) {
System.out.println("Linha ignorada: " + linha);
}
}
} catch (IOException e) {
System.out.println("Erro ao carregar: " + e);
}
return contatos;
}
}
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Agenda {
record Contato(String nome, String telefone, String email) {
String paraLinha() {
return nome + ";" + telefone + ";" + email;
}
}
static final Path ARQUIVO = Path.of("contatos.txt");
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
List<Contato> contatos = carregar();
System.out.println("=== Agenda da Ana === " + contatos.size() + " contato(s) carregado(s)");
while (true) {
System.out.println();
System.out.println("1) Listar 2) Adicionar 3) Buscar 4) Remover 0) Sair");
System.out.print("Opção: ");
String opcao = entrada.nextLine().trim();
switch (opcao) {
case "1" -> listar(contatos);
case "2" -> adicionar(entrada, contatos);
case "3" -> buscar(entrada, contatos);
case "4" -> remover(entrada, contatos);
case "0" -> {
System.out.println("Até logo!");
return;
}
default -> System.out.println("Opção inválida: " + opcao);
}
}
}
static void listar(List<Contato> contatos) {
if (contatos.isEmpty()) {
System.out.println("Nenhum contato.");
return;
}
for (int i = 0; i < contatos.size(); i++) {
Contato c = contatos.get(i);
System.out.println((i + 1) + ". " + c.nome() + " | " + c.telefone() + " | " + c.email());
}
System.out.println(contatos.size() + " contato(s).");
}
static void adicionar(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome: ");
String nome = entrada.nextLine().trim();
if (nome.isEmpty()) {
System.out.println("O nome não pode ficar vazio.");
return;
}
for (Contato c : contatos) {
if (c.nome().equalsIgnoreCase(nome)) {
System.out.println("Já existe um contato chamado " + c.nome() + ".");
return;
}
}
System.out.print("Telefone: ");
String telefone = entrada.nextLine().trim();
System.out.print("E-mail: ");
String email = entrada.nextLine().trim();
contatos.add(new Contato(nome, telefone, email));
salvar(contatos);
System.out.println("Adicionado: " + nome);
}
static void buscar(Scanner entrada, List<Contato> contatos) {
System.out.print("Buscar por: ");
String termo = entrada.nextLine().trim().toLowerCase();
int achados = 0;
for (Contato c : contatos) {
if (c.nome().toLowerCase().contains(termo)) {
System.out.println("- " + c.nome() + " | " + c.telefone() + " | " + c.email());
achados++;
}
}
if (achados == 0) {
System.out.println("Nenhum contato com \"" + termo + "\".");
}
}
static void remover(Scanner entrada, List<Contato> contatos) {
System.out.print("Nome para remover: ");
String nome = entrada.nextLine().trim();
for (Contato c : contatos) {
if (c.nome().equalsIgnoreCase(nome)) {
contatos.remove(c);
salvar(contatos);
System.out.println("Removido: " + c.nome());
return;
}
}
System.out.println("Não encontrei \"" + nome + "\".");
}
static void salvar(List<Contato> contatos) {
List<String> linhas = new ArrayList<>();
for (Contato c : contatos) {
linhas.add(c.paraLinha());
}
try {
Files.write(ARQUIVO, linhas);
} catch (IOException e) {
System.out.println("Erro ao salvar: " + e);
}
}
static List<Contato> carregar() {
List<Contato> contatos = new ArrayList<>();
if (!Files.exists(ARQUIVO)) {
return contatos;
}
try {
for (String linha : Files.readAllLines(ARQUIVO)) {
String[] partes = linha.split(";", -1);
if (partes.length == 3) {
contatos.add(new Contato(partes[0], partes[1], partes[2]));
} else if (!linha.isBlank()) {
System.out.println("Linha ignorada: " + linha);
}
}
} catch (IOException e) {
System.out.println("Erro ao carregar: " + e);
}
return contatos;
}
}
Exercícios
1. Como se lê o telefone de um record Contato c?
2. O que "Elisa;(41) 95555-3333;".split(";") devolve?
3. Por que o remover tem um return logo depois de contatos.remove(c)?
4. Por que a agenda lê tudo com nextLine()?
Complete para ler todas as linhas do arquivo:
Resumo
- Um
recordjunta dados relacionados e ganha construtor,nome(),toStringeequalsde graça; os componentes não mudam. ArrayListcresce sozinho;add,get,size,isEmpty,remove.- Com
nextLine()+trim()em tudo, nomes com espaço funcionam e o menu não "pula" perguntas. - Remover dentro de um for-each só é seguro se você sair do laço logo depois.
Files.writegrava uma lista de linhas;Files.readAllLineslê de volta.IOExceptionprecisa detry/catch(outhrows).split(";", -1)mantém campos vazios; confira o tamanho antes de usar as partes.
Próximo projeto: Sistema de Biblioteca, com várias classes conversando entre si.