Fundamentos de Desenvolvimento com Java: Console, Fluxo e Laços
TP2 com Scanner, validação de entrada, faixas, Random, bissexto e laços com condição de parada defensável
Este TP parece uma lista simples de console, mas cobra disciplina de fronteira: entrada confiável, regra de negócio clara e laço com parada explícita. O valor do material está em mostrar o caminho até a resposta, não só a resposta pronta.
Por isso cada exercício agora segue o mesmo formato: o que ele cobra, passos do algoritmo, um caso normal, uma borda e o código completo. Isso força você a validar a solução, não apenas copiá-la.
Como rodar
- IntelliJ: crie a classe do exercício, rode com
Rune acompanhe a entrada pelo console. - Terminal: compile com
javac Ex01.javae execute comjava Ex01. - Se quiser testar várias bordas, altere apenas a entrada. O valor didático aqui está em provar o comportamento, não em trocar o código a cada caso.
O que o exercício cobra
Ler nome completo, idade, nome da mãe e nome do pai, imprimir o cadastro e comparar o tamanho das strings com length().
Passos do algoritmo
- Ler tudo com nextLine() e converter a idade com Integer.parseInt().
- Exibir os quatro campos em um bloco organizado.
- Comparar nome do usuário com mãe e pai usando length() e operadores relacionais.
Teste manual
- Caso normal: nome "Ana Clara", mãe "Maria", pai "João Paulo" deve imprimir o cadastro completo e avaliar os dois booleanos.
- Borda: se dois nomes tiverem o mesmo tamanho, a comparação com > precisa resultar em false.
Ponto de atenção
Scanner com nextLine() + parse evita o clássico bug de quebrar a leitura ao misturar texto e número.
import java.util.Scanner;
public class Ex01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nome completo: ");
String nome = sc.nextLine();
System.out.print("Idade: ");
int idade = Integer.parseInt(sc.nextLine());
System.out.print("Nome da mãe: ");
String mae = sc.nextLine();
System.out.print("Nome do pai: ");
String pai = sc.nextLine();
System.out.println("\n=== Cadastro ===");
System.out.println("Nome: " + nome);
System.out.println("Idade: " + idade);
System.out.println("Mãe: " + mae);
System.out.println("Pai: " + pai);
System.out.println("\nComparação de tamanho (letras):");
System.out.println("Nome do usuário > nome da mãe? " + (nome.length() > mae.length()));
System.out.println("Nome do usuário > nome do pai? " + (nome.length() > pai.length()));
sc.close();
}
}O que o exercício cobra
Receber quatro notas, calcular a média aritmética e classificar o aluno com base em faixas.
Passos do algoritmo
- Acumular as quatro notas em um laço e dividir por 4.0.
- Imprimir a média formatada com duas casas.
- Avaliar as faixas na ordem correta: >= 7.0, depois >= 5.0, depois o restante.
Teste manual
- Caso normal: notas 8, 7, 6, 7 geram média 7.00 e devem aprovar.
- Borda: média 5.0 entra em recuperação; média 4.9 reprova; média 7.0 aprova.
Ponto de atenção
Aqui o aprendizado real é fronteira. 6.9 e 7.0 não podem cair na mesma condição.
import java.util.Scanner;
public class Ex02 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
double soma = 0.0;
for (int i = 1; i <= 4; i++) {
System.out.print("Nota " + i + ": ");
soma += Double.parseDouble(sc.nextLine());
}
double media = soma / 4.0;
System.out.printf("Média: %.2f%n", media);
if (media >= 7.0) {
System.out.println("Aprovado(a).");
} else if (media >= 5.0) {
System.out.println("Recuperação.");
} else {
System.out.println("Reprovado(a).");
}
sc.close();
}
}O que o exercício cobra
Receber um valor em reais e a moeda de destino, converter usando constantes definidas no próprio programa e exibir com duas casas.
Passos do algoritmo
- Definir as constantes de câmbio no topo do programa.
- Normalizar a moeda com trim() e toLowerCase() antes do switch.
- Converter e imprimir apenas quando a moeda estiver entre as opções aceitas.
Teste manual
- Caso normal: 100 BRL para dólar com USD = 5.00 deve imprimir 20.00.
- Borda: entrada "iene" deve cair no default e informar moeda inválida.
Ponto de atenção
O enunciado manda definir as taxas no código. Se o professor exigir outro valor, ajuste apenas as constantes USD, EUR e GBP.
import java.util.Scanner;
public class Ex03 {
public static void main(String[] args) {
final double USD = 5.00; // 1 USD = 5.00 BRL (exemplo)
final double EUR = 5.50; // exemplo
final double GBP = 6.40; // exemplo
Scanner sc = new Scanner(System.in);
System.out.print("Valor em reais (BRL): ");
double brl = Double.parseDouble(sc.nextLine());
System.out.print("Moeda destino (dolar/euro/libra): ");
String moeda = sc.nextLine().trim().toLowerCase();
if (moeda.equals("dólar")) moeda = "dolar"; // normaliza
double convertido;
switch (moeda) {
case "dolar":
convertido = brl / USD;
System.out.printf("USD: %.2f%n", convertido);
break;
case "euro":
convertido = brl / EUR;
System.out.printf("EUR: %.2f%n", convertido);
break;
case "libra":
convertido = brl / GBP;
System.out.printf("GBP: %.2f%n", convertido);
break;
default:
System.out.println("Moeda inválida. Use: dolar/euro/libra.");
}
sc.close();
}
}O que o exercício cobra
Ler dia, mês e ano de nascimento, validar a data e calcular a idade em dias usando uma contagem absoluta de dias.
Passos do algoritmo
- Validar se a data existe antes de qualquer cálculo.
- Converter nascimento e data atual para dias absolutos desde um ponto comum.
- Subtrair os totais e imprimir a diferença em dias.
Teste manual
- Caso normal: uma data válida deve produzir um total positivo de dias.
- Borda: 28/02/2024 -> 01/03/2024 precisa respeitar o dia extra; 1900 não é bissexto e 2000 é.
Ponto de atenção
Dias absolutos ensinam mais do que subtrair datas no improviso, porque forçam uma lógica verificável para meses e anos bissextos. Aqui o uso de LocalDate.now() serve apenas para obter a data atual; se o professor exigir um caminho 100% sem API, basta ler a data de hoje via Scanner e reutilizar exatamente a mesma conta manual.
import java.util.Scanner;
import java.time.LocalDate;
public class Ex04 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Dia nascimento: ");
int diaN = Integer.parseInt(sc.nextLine());
System.out.print("Mês nascimento: ");
int mesN = Integer.parseInt(sc.nextLine());
System.out.print("Ano nascimento: ");
int anoN = Integer.parseInt(sc.nextLine());
if (!dataValida(diaN, mesN, anoN)) {
System.out.println("Data de nascimento inválida.");
sc.close();
return;
}
LocalDate hoje = LocalDate.now();
int diaH = hoje.getDayOfMonth();
int mesH = hoje.getMonthValue();
int anoH = hoje.getYear();
long absN = diasAbsolutos(diaN, mesN, anoN);
long absH = diasAbsolutos(diaH, mesH, anoH);
long idadeDias = absH - absN;
System.out.println("Idade total em dias: " + idadeDias);
sc.close();
}
static boolean dataValida(int dia, int mes, int ano) {
if (ano < 1) return false;
if (mes < 1 || mes > 12) return false;
int max = diasNoMes(mes, ano);
return dia >= 1 && dia <= max;
}
static int diasNoMes(int mes, int ano) {
int[] base = {0,31,28,31,30,31,30,31,31,30,31,30,31};
if (mes == 2 && isBissexto(ano)) return 29;
return base[mes];
}
static long diasAbsolutos(int dia, int mes, int ano) {
int y = ano - 1;
long total = 365L * y + qtdBissextosAte(y);
for (int m = 1; m < mes; m++) {
total += diasNoMes(m, ano);
}
total += dia;
return total;
}
static long qtdBissextosAte(int ano) {
return (ano / 4L) - (ano / 100L) + (ano / 400L);
}
static boolean isBissexto(int ano) {
return (ano % 400 == 0) || (ano % 4 == 0 && ano % 100 != 0);
}
}O que o exercício cobra
Receber o valor de uma compra e calcular desconto e total final conforme a faixa de preço.
Passos do algoritmo
- Ler o valor e decidir a taxa de desconto pela faixa.
- Calcular desconto = valor * taxa.
- Imprimir valor original, desconto e valor final.
Teste manual
- Caso normal: compra de 800.00 deve aplicar 5% e imprimir os três valores.
- Borda: 1000.00 ainda está na faixa de 5%; 1000.01 passa para 10%.
Ponto de atenção
Este é um bom exercício para treinar a leitura exata de intervalos. Um >= no lugar errado muda o resultado inteiro.
import java.util.Scanner;
public class Ex05 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Valor da compra: ");
double valor = Double.parseDouble(sc.nextLine());
double taxa;
if (valor > 1000.0) taxa = 0.10;
else if (valor >= 500.0) taxa = 0.05;
else taxa = 0.0;
double desconto = valor * taxa;
double finalValor = valor - desconto;
System.out.printf("Original: R$ %.2f%n", valor);
System.out.printf("Desconto: R$ %.2f%n", desconto);
System.out.printf("Final: R$ %.2f%n", finalValor);
sc.close();
}
}O que o exercício cobra
Receber um ano e decidir se ele é bissexto segundo a regra completa.
Passos do algoritmo
- Ler o ano informado pelo usuário.
- Aplicar a condição: múltiplo de 400 entra, múltiplo de 100 sai, demais múltiplos de 4 entram.
- Imprimir a mensagem final conforme o booleano.
Teste manual
- Caso normal: 2024 deve ser classificado como bissexto.
- Borda: 1900 deve ser falso; 2000 deve ser verdadeiro.
Ponto de atenção
Nem todo múltiplo de 4 é bissexto. O caso de século é exatamente o tipo de borda que costuma ser esquecida.
import java.util.Scanner;
public class Ex06 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Ano: ");
int ano = Integer.parseInt(sc.nextLine());
boolean b = (ano % 400 == 0) || (ano % 4 == 0 && ano % 100 != 0);
System.out.println(b ? "É bissexto." : "Não é bissexto.");
sc.close();
}
}O que o exercício cobra
Receber a renda anual e calcular imposto pela soma das faixas, não pela aplicação de uma única alíquota final.
Passos do algoritmo
- Ler a renda anual bruta.
- Calcular o imposto somando o resultado de cada faixa tributável.
- Subtrair o imposto da renda para obter o salário líquido.
Teste manual
- Caso normal: renda 90000 deve tributar 30000 a 10% e 30000 a 20%, totalizando 9000 no exemplo.
- Borda: renda 30000 paga zero; renda 30000.01 tributa apenas a parte acima do limite.
Ponto de atenção
O objetivo pedagógico é a mecânica progressiva. Como o enunciado não entrega uma tabela oficial de imposto, as faixas usadas aqui funcionam como placeholder didático: se o professor usar outra tabela, troque as faixas, não o raciocínio.
import java.util.Scanner;
public class Ex07 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Salário bruto anual: ");
double renda = Double.parseDouble(sc.nextLine());
// Exemplo de tabela (AJUSTE):
// até 30000: 0%
// 30000–60000: 10%
// 60000–120000: 20%
// acima: 30%
double imposto =
tributaFaixa(renda, 0, 30000, 0.00) +
tributaFaixa(renda, 30000, 60000, 0.10) +
tributaFaixa(renda, 60000, 120000, 0.20) +
tributaFaixa(renda, 120000, Double.POSITIVE_INFINITY, 0.30);
double liquido = renda - imposto;
System.out.printf("Imposto a pagar: R$ %.2f%n", imposto);
System.out.printf("Salário líquido: R$ %.2f%n", liquido);
sc.close();
}
static double tributaFaixa(double renda, double inicio, double fim, double aliquota) {
if (renda <= inicio) return 0.0;
double base = Math.min(renda, fim) - inicio;
return base * aliquota;
}
}O que o exercício cobra
Receber três lados, validar se existe triângulo e classificar como equilátero, isósceles ou escaleno.
Passos do algoritmo
- Ler os três lados.
- Verificar se os lados são positivos e obedecem à desigualdade triangular.
- Somente depois classificar pelo padrão de igualdade entre lados.
Teste manual
- Caso normal: 3, 4 e 5 deve resultar em escaleno.
- Borda: 1, 2 e 3 não formam triângulo; 2, 2 e 2 deve resultar em equilátero.
Ponto de atenção
Em fundamentos isso passa com double, mas vale a precisão didática: comparação exata com == em double pode trair. Se quiser máxima segurança didática, prefira int ou use tolerância.
import java.util.Scanner;
public class Ex08 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Lado A: ");
double a = Double.parseDouble(sc.nextLine());
System.out.print("Lado B: ");
double b = Double.parseDouble(sc.nextLine());
System.out.print("Lado C: ");
double c = Double.parseDouble(sc.nextLine());
boolean valido = a > 0 && b > 0 && c > 0
&& a + b > c && a + c > b && b + c > a;
if (!valido) {
System.out.println("Não forma um triângulo válido.");
} else if (a == b && b == c) {
System.out.println("Equilátero.");
} else if (a == b || a == c || b == c) {
System.out.println("Isósceles.");
} else {
System.out.println("Escaleno.");
}
sc.close();
}
}O que o exercício cobra
Cadastrar uma senha e repetir a leitura até que a nova entrada seja idêntica à senha original.
Passos do algoritmo
- Ler a senha inicial.
- Entrar em laço pedindo a confirmação.
- Usar equals() para comparar e sair apenas quando houver coincidência.
Teste manual
- Caso normal: senha "abc123", tentativa errada e depois correta devem resultar em uma mensagem final de sucesso.
- Borda: mesmo conteúdo em outro objeto String continua funcionando, porque a comparação é por equals(), não por ==.
Ponto de atenção
Aqui o while existe para cumprir um contrato claro: repetir enquanto a confirmação estiver errada.
import java.util.Scanner;
public class Ex09 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Cadastre uma senha: ");
String senha = sc.nextLine();
while (true) {
System.out.print("Digite novamente: ");
String tentativa = sc.nextLine();
if (tentativa.equals(senha)) break;
System.out.println("Senha incorreta. Tente novamente.");
}
System.out.println("Senha confirmada com sucesso.");
sc.close();
}
}O que o exercício cobra
Sortear um número com Random, aceitar vários palpites e informar se o próximo palpite deve ser maior ou menor.
Passos do algoritmo
- Sortear um inteiro entre 1 e 100.
- Ler palpites em laço contínuo.
- Rejeitar palpites fora do intervalo e dar dica maior/menor até acertar.
Teste manual
- Caso normal: se o segredo for 70 e o palpite for 50, o programa deve responder "Maior.".
- Borda: 0 ou 101 devem ser rejeitados antes de comparar com o segredo.
Ponto de atenção
Random aqui não serve para “efeito especial”; serve para exercitar laço com estado e feedback progressivo.
import java.util.Random;
import java.util.Scanner;
public class Ex10 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Random rnd = new Random();
int secreto = rnd.nextInt(100) + 1; // 1..100
int palpite;
while (true) {
System.out.print("Palpite (1 a 100): ");
palpite = Integer.parseInt(sc.nextLine());
if (palpite < 1 || palpite > 100) {
System.out.println("Fora do intervalo. Digite de 1 a 100.");
continue;
}
if (palpite < secreto) System.out.println("Maior.");
else if (palpite > secreto) System.out.println("Menor.");
else break;
}
System.out.println("Acertou!");
sc.close();
}
}O que o exercício cobra
Ler um valor inicial e um incremento, imprimir a sequência até o primeiro valor que ultrapassar 100.
Passos do algoritmo
- Ler valor inicial e incremento.
- Validar se o incremento é positivo antes do laço.
- Imprimir cada termo e encerrar quando o valor atual ultrapassar 100.
Teste manual
- Caso normal: 98 e 3 deve imprimir 98, 101.
- Borda: 101 e 3 imprime só 101; incremento 0 deve ser recusado para evitar loop infinito.
Ponto de atenção
O detalhe realmente importante é interpretar “até ultrapassar 100” ao pé da letra: o valor que rompe a barreira ainda precisa aparecer.
import java.util.Scanner;
public class Ex11 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Valor inicial: ");
int atual = Integer.parseInt(sc.nextLine());
System.out.print("Incremento: ");
int inc = Integer.parseInt(sc.nextLine());
if (inc <= 0) {
System.out.println("Incremento deve ser > 0 para a sequência terminar.");
sc.close();
return;
}
boolean primeiro = true;
while (true) {
if (!primeiro) System.out.print(", ");
System.out.print(atual);
primeiro = false;
if (atual > 100) break; // garante que o “cara que passou” aparece
atual += inc;
}
System.out.println();
sc.close();
}
}O que o exercício cobra
Ler uma frase, limpar as bordas, separar por espaços em branco e contar quantas palavras existem.
Passos do algoritmo
- Ler a frase e aplicar trim().
- Se a frase ficar vazia, retornar 0.
- Separar com split("\\s+") e contar os elementos.
Teste manual
- Caso normal: "um dois tres" deve resultar em 3.
- Borda: frase vazia retorna 0; múltiplos espaços entre palavras não podem inflar a contagem.
Ponto de atenção
Esse exercício ensina uma forma simples de impedir que “espaço sobrando” vire palavra fantasma.
import java.util.Scanner;
public class Ex12 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Digite uma frase: ");
String frase = sc.nextLine().trim();
if (frase.isEmpty()) {
System.out.println("Total de palavras: 0");
sc.close();
return;
}
String[] palavras = frase.split("\\s+");
int contador = 0;
for (int i = 0; i < palavras.length; i++) {
contador++;
}
System.out.println("Total de palavras: " + contador);
sc.close();
}
}Perguntas que você precisa conseguir responder
- Por que
nextLine()+ parse é mais previsível quando há texto e número? - Por que dias absolutos deixam o EX04 mais confiável do que subtração improvisada de datas?
- Por que imposto progressivo precisa ser calculado por faixa?
- Por que o EX11 valida o incremento antes de entrar no laço?