Agora que extraímos o primeiro método para tornar nosso código um pouco mais legível, precisamos continuar extraindo todos os blocos de código da função main() que podem se tornar métodos.
Porém, antes disso, gostaria que corrigíssemos uma pequena coisa em nosso código.
Anteriormente, nós criamos o método cadastrarAbrigo(), que será a opção número 1. Na verdade, a opção 1 não é cadastrarAbrigo(), e sim listarAbrigo(). Se olharmos no bloco while, dentro da função main(), no System.out.println(), a opção 1 é "Listar abrigos cadastrados".
Para resolver esse problema, precisamos rolar a tela até a nossa função de cadastrarAbrigo() e mudaremos o seu nome de cadastrar para listar.
private static void listarAbrigo() throws IOException, InterruptedException {
}
Feito isso, vamos copiar o listarAbrigo() com "Ctrl+C" e referenciá-lo lá em cima, onde adicionaremos cadastrarAbrigo(), porque agora o nosso código parou de compilar, ele não encontra essa função.
if (opcaoEscolhida == 1) {
listarAbrigo();
}
Extraindo os Métodos
Agora, precisamos criar o método para a opção 2 que é, de fato, cadastrarAbrigo(). Voltaremos ao fim do arquivo e, abaixo da função listarAbrigo(), criaremos a cadastrarAbrigo().
Sabemos que precisamos criar uma função privada (private), pois estamos trabalhando no mesmo arquivo. Dentro do mesmo arquivo, podemos usar o modificador private para referenciar na mesma classe. Este método precisa ser estático (static), pois estamos chamando através de uma função main() que é estática.
Ela não tem retorno, então será void. Por fim, adicionaremos o nome cadastrarAbrigo, abriremos um bloco de parênteses (())e também um bloco de chaves ({}).
private static void cadastrarAbrigo(){
}
Agora, vamos voltar à função main() para extrair o código do else if que contém a opcaoEscolhida == 2, recortando o trecho que se inicia no System.out.println() da frase "Digite o nome do abrigo", e termina no fechamento das chaves do bloco else if que devolve a mensagem "Erro ao cadastrar o abrigo".
}else if (opcaoEscolhida == 2) {
System.out.println("Digite o nome do abrigo:");
String nome = new Scanner(System.in).nextLine();
System.out.println("Digite o telefone do abrigo:");
String telefone = new Scanner(System.in).nextLine();
System.out.println("Digite o email do abrigo:");
String email = new Scanner(System.in).nextLine();
JsonObject json = new JsonObject();
json.addProperty("nome", nome);
json.addProperty("telefone", telefone);
json.addProperty("email", email);
HttpClient client = HttpClient.newHttpClient();
String uri = "http:
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(uri))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json.toString()))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
String responseBody = response.body();
if (statusCode == 200) {
System.out.println("Abrigo cadastrado com sucesso!");
System.out.println(responseBody);
} else if (statusCode == 400 || statusCode == 500) {
System.out.println("Erro ao cadastrar o abrigo:");
System.out.println(responseBody);
}
}
Voltaremos à função cadastrarAbrigo() que criamos no final da nossa classe e colaremos o conteúdo recortado entre suas chaves.
private static void cadastrarAbrigo(){
System.out.println("Digite o nome do abrigo:");
String nome = new Scanner(System.in).nextLine();
System.out.println("Digite o telefone do abrigo:");
String telefone = new Scanner(System.in).nextLine();
System.out.println("Digite o email do abrigo:");
String email = new Scanner(System.in).nextLine();
JsonObject json = new JsonObject();
json.addProperty("nome", nome);
json.addProperty("telefone", telefone);
json.addProperty("email", email);
HttpClient client = HttpClient.newHttpClient();
String uri = "http:
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(uri))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json.toString()))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
String responseBody = response.body();
if (statusCode == 200) {
System.out.println("Abrigo cadastrado com sucesso!");
System.out.println(responseBody);
} else if (statusCode == 400 || statusCode == 500) {
System.out.println("Erro ao cadastrar o abrigo:");
System.out.println(responseBody);
}
}
Notaremos que o send(), do nosso método não está compilando, ou seja, está com uma linha vermelha embaixo dele.
O método send() pode lançar uma exceção checada (Checked Exception). Conforme vimos anteriormente, esta é uma exceção que precisamos tratar através de um try catch ou deixar explícito na assinatura do método que ela pode ser lançada. Se não fizermos isso, nossa classe não vai compilar.
Vamos colocar o cursor sobre o send(), a IDE - nesse caso, o IntelliJ — exibir uma caixa dde diálogo com a opção de adicionar as exceções checadas na assinatura do método ("Add exceptions to method signature").
Ao selecioná-la, ele vai adicionar um throws IOException, InterruptedException para deixar explícito na primeira linha do método cadastrarAbrigo() que este pode lançar uma exceção IOExceptional ou InterruptedExceptional que não estamos tratando através de um try-catch.
private static void cadastrarAbrigo() throws IOException, InterruptedException {
System.out.println("Digite o nome do abrigo:");
String nome = new Scanner(System.in).nextLine();
System.out.println("Digite o telefone do abrigo:");
String telefone = new Scanner(System.in).nextLine();
System.out.println("Digite o email do abrigo:");
String email = new Scanner(System.in).nextLine();
JsonObject json = new JsonObject();
json.addProperty("nome", nome);
json.addProperty("telefone", telefone);
json.addProperty("email", email);
HttpClient client = HttpClient.newHttpClient();
String uri = "http:
HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(uri))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json.toString()))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
String responseBody = response.body();
if (statusCode == 200) {
System.out.println("Abrigo cadastrado com sucesso!");
System.out.println(responseBody);
} else if (statusCode == 400 || statusCode == 500) {
System.out.println("Erro ao cadastrar o abrigo:");
System.out.println(responseBody);
}
}
Por fim, vamos referenciar o cadastrarAbrigo() no método main(), entre as chaves da opcaoEscolhida == 2.
public class AdopetConsoleApplication {
public static void main(String[] args) {
if (opcaoEscolhida == 1) {
listarAbrigo();
} else if (opcaoEscolhida == 2) {
cadastrarAbrigo();
}
}
Com isso, temos mais uma função. Agora temos uma função para a opção 1 e outra para a opção 2.
Vamos prosseguir, extraindo todo o código que está dentro do else if da opção 3 para uma nova função. Nesse caso, a função é "Listar pets do abrigo". Portanto, o nome da nossa função será listarPetsDoAbrigo().
Voltaremos ao final da nossa classe para criar a nova função private static void listarPetsDoAbrigo() sem nenhum parâmetro. à sua direita, abriremos e fecharemos chaves.
private static void listarPetsDoAbrigo(){
}
Voltando à função main(), extrairemos com "Ctrl+C" o código do bloco else if da opção 3 para migrá-lo para a nova função. O bloco inicia no System.out.println() da mensagem "Digite o id ou nome do abrigo" e termina antes do else if da opção 4.
Voltaremos para a função listarPetsDoAbrigo() que acabamos de criar e pressionaremos Ctrl V para colar o código.
private static void listarPetsDoAbrigo(){
System.out.println("Digite o id ou nome do abrigo:");
String idOuNome = new Scanner(System.in).nextLine();
HttpClient client = HttpClient.newHttpClient();
String uri = "http:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
if (statusCode == 404 || statusCode == 500) {
System.out.println("ID ou nome não cadastrado!");
}
String responseBody = response.body();
JsonArray jsonArray = JsonParser.parseString(responseBody).getAsJsonArray();
System.out.println("Pets cadastrados:");
for (JsonElement element : jsonArray) {
JsonObject jsonObject = element.getAsJsonObject();
long id = jsonObject.get("id").getAsLong();
String tipo = jsonObject.get("tipo").getAsString();
String nome = jsonObject.get("nome").getAsString();
String raca = jsonObject.get("raca").getAsString();
int idade = jsonObject.get("idade").getAsInt();
System.out.println(id +" - " +tipo +" - " +nome +" - " +raca +" - " +idade +" ano(s)");
}
}
Vamos notar que o send() exibirá o mesmo erro acusado pela IDE com um traço vermelho abaixo do código. Para evitar isso, adicionaremos as exceções na assinatura do método.
private static void listarPetsDoAbrigo() throws IOException, InterruptedException {
System.out.println("Digite o id ou nome do abrigo:");
String idOuNome = new Scanner(System.in).nextLine();
HttpClient client = HttpClient.newHttpClient();
String uri = "http:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
if (statusCode == 404 || statusCode == 500) {
System.out.println("ID ou nome não cadastrado!");
}
String responseBody = response.body();
JsonArray jsonArray = JsonParser.parseString(responseBody).getAsJsonArray();
System.out.println("Pets cadastrados:");
for (JsonElement element : jsonArray) {
JsonObject jsonObject = element.getAsJsonObject();
long id = jsonObject.get("id").getAsLong();
String tipo = jsonObject.get("tipo").getAsString();
String nome = jsonObject.get("nome").getAsString();
String raca = jsonObject.get("raca").getAsString();
int idade = jsonObject.get("idade").getAsInt();
System.out.println(id +" - " +tipo +" - " +nome +" - " +raca +" - " +idade +" ano(s)");
}
}
Copiaremos o nome da nossa função, listarPetsDoAbrigo(), subiremos ao interior das chaves do else if que continha o código recortado e configuraremos a opção 3 pela referência à função.
public class AdopetConsoleApplication {
public static void main(String[] args) {
if (opcaoEscolhida == 1) {
listarAbrigo();
} else if (opcaoEscolhida == 2) {
cadastrarAbrigo();
} else if (opcaoEscolhida == 3){
listarPetsDoAbrigo()
}
}
Estamos encurtando a função main(), que estava muito longa e cheia de código. Para isso, damos comportamentos específicos para a nossa classe: uma para listar pets, outra para listar abrigos e outra para cadastro. Esse é o nosso objetivo.
Por último, temos a opção 4, "Importar pets do abrigo". Essa função lê o arquivo pets.csv, mas poderíamos referenciar outros. Ao importar esse arquivo, o sistema lerá todo o seu conteúdo e registrará na nossa API.
Vamos criar uma nova função, private static void importarPetsDoAbrigo() sem parâmetros, abaixo das funções anteriores.
private static void importarPetsDoAbrigo() {
}
Copiaremos todo o código do else if da opção 4 e colaremos entre as chaves da nova função importarPetsDoAbrigo(). Esse bloco se inicia no System.out.println() da frase "Digite o id ou nome do abrigo" e termina na linha reader.close() antes do bloco da opção 5.
private static void importarPetsDoAbrigo() {
System.out.println("Digite o id ou nome do abrigo:");
String idOuNome = new Scanner(System.in).nextLine();
System.out.println("Digite o nome do arquivo CSV:");
String nomeArquivo = new Scanner(System.in).nextLine();
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader(nomeArquivo));
} catch (IOException e) {
System.out.println("Erro ao carregar o arquivo: " + nomeArquivo);
continue;
}
String line;
while ((line = reader.readLine()) != null) {
String[] campos = line.split(",");
String tipo = campos[0];
String nome = campos[1];
String raca = campos[2];
int idade = Integer.parseInt(campos[3]);
String cor = campos[4];
Float peso = Float.parseFloat(campos[5]);
JsonObject json = new JsonObject();
json.addProperty("tipo", tipo.toUpperCase());
json.addProperty("nome", nome);
json.addProperty("raca", raca);
json.addProperty("idade", idade);
json.addProperty("cor", cor);
json.addProperty("peso", peso);
HttpClient client = HttpClient.newHttpClient();
String uri = "http:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json.toString()))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
String responseBody = response.body();
if (statusCode == 200) {
System.out.println("Pet cadastrado com sucesso: " + nome);
} else if (statusCode == 404) {
System.out.println("Id ou nome do abrigo não encontrado!");
break;
} else if (statusCode == 400 || statusCode == 500) {
System.out.println("Erro ao cadastrar o pet: " + nome);
System.out.println(responseBody);
break;
}
}
reader.close();
}
Temos a mesma questão anterior com o método close(), ele pode lançar uma exceção do tipo IOException. Vamos selecionar a opção "Add exception to method signature" para adicionar essa exceção à assinatura do método.
O send() também pode causar erro, conforme observamos na função anterior. Portanto, adicionaremos também as duas exceções que podem ser exibidas nele.
private static void importarPetsDoAbrigo() throws IOException, InterruptedException {
System.out.println("Digite o id ou nome do abrigo:");
String idOuNome = new Scanner(System.in).nextLine();
System.out.println("Digite o nome do arquivo CSV:");
String nomeArquivo = new Scanner(System.in).nextLine();
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader(nomeArquivo));
} catch (IOException e) {
System.out.println("Erro ao carregar o arquivo: " + nomeArquivo);
continue;
}
String line;
while ((line = reader.readLine()) != null) {
String[] campos = line.split(",");
String tipo = campos[0];
String nome = campos[1];
String raca = campos[2];
int idade = Integer.parseInt(campos[3]);
String cor = campos[4];
Float peso = Float.parseFloat(campos[5]);
JsonObject json = new JsonObject();
json.addProperty("tipo", tipo.toUpperCase());
json.addProperty("nome", nome);
json.addProperty("raca", raca);
json.addProperty("idade", idade);
json.addProperty("cor", cor);
json.addProperty("peso", peso);
HttpClient client = HttpClient.newHttpClient();
String uri = "http:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json.toString()))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
String responseBody = response.body();
if (statusCode == 200) {
System.out.println("Pet cadastrado com sucesso: " + nome);
} else if (statusCode == 404) {
System.out.println("Id ou nome do abrigo não encontrado!");
break;
} else if (statusCode == 400 || statusCode == 500) {
System.out.println("Erro ao cadastrar o pet: " + nome);
System.out.println(responseBody);
break;
}
}
reader.close();
}
Precisamos resolver outro problema. Dentro do while do nosso novo método, o reader() não está sendo reconhecido. Se posicionarmos o cursor em cima dele, veremos uma mensagem da IDE informando que precisamos inicializar a variável reader, declarada com o tipo BufferedReader, abaixo da linha String nomeArquivo.
Com a mudança do método main(), precisaremos instanciar a variável reader. Vamos inicializá-la como nula, porque quando o tryabaixo dela for acionado, o reader será instanciado e dentro do while, teremos esse objeto.
BufferedReader reader = null;
O bloco catch abaixo da variável reader não está compilando, pois o continue está indicado pelo sublinhado vermelho. Vamos verificar o que está acontecendo.
Quando esse código estava dentro do main(), estava dentro de um loop (laço) while. A ideia era que, se ocorresse qualquer erro no momento da importação de um arquivo, ele registraria um erro ao carregar o arquivo e continuaria nas opções.
Porém, após extrairmos o código do laço, o continue perdeu o seu sentido, já que não estamos mais dentro de um ciclo. Portanto, vamos removê-lo, mas ainda precisamos pensar em uma estratégia para corrigir isso, já que se caírmos no catch, não voltaremos para o menu.
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(nomeArquivo));
} catch (IOException e) {
System.out.println("Erro ao carregar o arquivo: " + nomeArquivo);
}
O código completo da função importarPetsDoAbrigo() pode ser vista abaixo.
private static void importarPetsDoAbrigo() throws IOException, InterruptedException {
System.out.println("Digite o id ou nome do abrigo:");
String idOuNome = new Scanner(System.in).nextLine();
System.out.println("Digite o nome do arquivo CSV:");
String nomeArquivo = new Scanner(System.in).nextLine();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(nomeArquivo));
} catch (IOException e) {
System.out.println("Erro ao carregar o arquivo: " + nomeArquivo);
}
String line;
while ((line = reader.readLine()) != null) {
String[] campos = line.split(",");
String tipo = campos[0];
String nome = campos[1];
String raca = campos[2];
int idade = Integer.parseInt(campos[3]);
String cor = campos[4];
Float peso = Float.parseFloat(campos[5]);
JsonObject json = new JsonObject();
json.addProperty("tipo", tipo.toUpperCase());
json.addProperty("nome", nome);
json.addProperty("raca", raca);
json.addProperty("idade", idade);
json.addProperty("cor", cor);
json.addProperty("peso", peso);
HttpClient client = HttpClient.newHttpClient();
String uri = "http:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(uri))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json.toString()))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
String responseBody = response.body();
if (statusCode == 200) {
System.out.println("Pet cadastrado com sucesso: " + nome);
} else if (statusCode == 404) {
System.out.println("Id ou nome do abrigo não encontrado!");
break;
} else if (statusCode == 400 || statusCode == 500) {
System.out.println("Erro ao cadastrar o pet: " + nome);
System.out.println(responseBody);
break;
}
}
reader.close();
}
Esse não é o nosso objetivo atual, mas é algo que precisamos considerar. O foco era extrair todos os métodos e códigos do main(), e nisso fomos bem sucedidos.
Agora, vamos inicializar a aplicação e conferir se está tudo correto.
No explorador lateral, veremos na pasta do projeto que temos a API api.jar que executa todas as operações através do nosso console público. Podemos instanciá-la utilizando o nosso terminal.
Abriremos o terminal na aba inferior do IntelliJ, na qual digitaremos e rodaremos o comando abaixo, onde api.jar é o nome do arquivo. Com isso, ele vai instanciar e inicializar a nossa API. Agora, posso minimizar esse terminal, clicando no ícone de minimizar no canto superior direito da aba.
Voltando à função main(), vamos clicar no ícone de "Play" à esquerda para inicializar o projeto. Com isso, veremos que mesmo com todas as mudanças e extraindo métodos, o comportamento da aplicação não mudou.
Por exemplo, se quisermos listar um abrigo cadastrado, selecionando a opção "1" no terminal e pressionar "Enter", ele retornará a mensagem "Abrigos cadastrados" e um campo vazio. Esse é o mesmo comportamento que tínhamos anteriormente.
Se escolhermos a opção 3, ele solicitará o ID ou o nome do abrigo. Como não temos nenhum abrigo cadastrado, vamos fornecer o ID '1', como exemplo. A resposta será nula, pois não temos nenhum animal de estimação cadastrado.
A seguir, precisamos tratar nossa aplicação para que estes comportamentos sejam normalizados, no sentido de termos dados para trabalhar. Por exemplo, toda vez que listarmos os animais de estimação, ele deve retornar os animais cadastrados.
Vimos em um momento que ele não retornou dados e consequentemente, exibiu uma exceção. Este não é um comportamento que desejamos em nossa aplicação.
Como podemos criar um comportamento que seja mais amigável e comum na nossa aplicação? Isso será feito à medida que avançarmos nas aulas e refatorarmos nosso código.