18  Respostas e pistas

Consulte depois de tentar resolver as atividades

Este apêndice apresenta critérios de conferência e caminhos possíveis. A solução pode usar nomes ou estruturas diferentes e ainda estar correta se respeitar o contrato proposto. Os programas completos estão em examples/src.

Fluxo recomendado: tentar a atividade, executar e observar, consultar uma pista, revisar a solução e tentar novamente.

Como usar as respostas sem perder a oportunidade de praticar.

18.1 Primeiros passos

A classe pública e o arquivo devem ter o mesmo nome. A sequência correta é:

javac NomeDaClasse.java
java NomeDaClasse

Se o compilador apontar ';' expected, revise a instrução indicada e também a linha anterior.

18.2 Variáveis, tipos e entrada

Uma solução possível usa String para nome e cidade e int para horas. A carga de quatro semanas é horasSemanais * 4. Aplique strip() aos textos e leia números com Integer.parseInt(scanner.nextLine()).

18.3 Condicionais

A classificação deve testar os limites em ordem:

if (horas < 3) {
    return "ritmo inicial";
} else if (horas <= 6) {
    return "ritmo consistente";
}
return "ritmo intensivo";

O valor 3 pertence ao intervalo consistente; o valor 6 também.

18.4 Repetição

Mantenha contadores separados para mensagens válidas, desconhecidas e caracteres. Atualize-os somente depois de rejeitar entrada vazia e antes de verificar o limite máximo.

18.5 Métodos

Uma implementação possível de comando conhecido:

static boolean ehComandoConhecido(String entrada) {
    return switch (normalizarComando(entrada)) {
        case "oi", "ajuda", "dica", "sair" -> true;
        default -> false;
    };
}

O método não deve imprimir; ele apenas devolve uma decisão.

18.6 Arrays

Para o array {30, 40, 20, 50, 10}, o total é 150, a média é 30.0, o maior é 50 e o menor é 10. Antes de inicializar maior e menor com o primeiro elemento, rejeite length == 0.

18.7 Listas

Para manter somente os dez últimos itens:

historico.add(mensagem);
if (historico.size() > 10) {
    historico.remove(0);
}

Para consultar as três últimas, calcule Math.max(0, size - 3) e devolva uma cópia do subintervalo.

18.8 Classes e objetos

totalMensagens() deve consultar a lista, não manter um segundo contador que possa ficar dessincronizado. O construtor rejeita null e isBlank(). List.copyOf protege a estrutura interna.

18.9 Exceções e arquivos

Capture NumberFormatException dentro do laço de leitura. Propague IOException no método de persistência e capture-a na aplicação de console. Assim, cada camada decide apenas o erro que sabe apresentar.

18.10 Chatbot integrado

A consulta ao histórico deve ocorrer antes do registro da interação. O comando sair é tratado pelo laço externo. Entradas vazias não passam para o método que registra.

18.11 Design orientado a objetos

A extração está correta quando Historico pode ser testado sem Scanner e quando ProcessadorComandos não conhece arquivo ou console. O comportamento observado pela pessoa usuária deve permanecer igual.

18.12 Herança

Aviso extends MensagemBot chama super("aviso") e sobrescreve texto(). Se avisos precisarem apenas conter uma mensagem variável, composição pode ser mais simples que criar muitas subclasses.

18.13 Interfaces e polimorfismo

ComandoSobre implementa Comando e é adicionado à coleção. O método processar não deve ganhar outro if ou case.

18.14 Generics e coleções

Use putIfAbsent para detectar chave duplicada. Normalize a chave no registro e na consulta. List.copyOf e Map.copyOf são adequados para expor visões imutáveis.

18.15 Testes e refatoração

Faça um teste falhar alterando temporariamente o valor esperado. A mensagem deve identificar descrição, esperado e obtido. Restaure o teste antes de continuar. Uma refatoração só termina quando todos os casos voltam a passar.

18.16 Projeto final

Antes de consultar a referência, confirme:

Compare sua solução com Capitulo16Projeto.java e registre ao menos uma decisão que você manteria e uma que mudaria.