Introdução
Em Programação I e na revisão de OO, você trabalhou com classes, objetos e herança em Java. Nesta página vamos olhar para três temas que aparecem em praticamente todo sistema real: contratos de código (interfaces), erros em tempo de execução (exceções) e persistência simples com arquivos, agora em JavaScript.
Configuração do ambiente para os exemplos
Podemos reutilizar a mesma estrutura de arquivo HTML da revisão de OO, alterando apenas o nome do arquivo JavaScript para esta unidade.
Opção 1 – Navegador (recomendado)
- Crie uma pasta, por exemplo
prog2-interfaces-excecoes. -
Dentro da pasta, crie um arquivo chamado
index.htmlcom o conteúdo abaixo.
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<title>Interfaces, exceções e arquivos - Programação II</title>
</head>
<body>
<h1>Interfaces, exceções e manipulação de arquivos</h1>
<p>Abra o console do navegador para ver a saída dos exemplos.</p>
<script src="interfaces-excecoes-arquivos.js"></script>
</body>
</html>
-
Crie um arquivo
interfaces-excecoes-arquivos.jsna mesma pasta. É nele que você vai colar e adaptar os exemplos desta página. - Abra o
index.htmlno navegador. - Pressione F12 e acesse a aba Console para acompanhar a saída dos códigos.
src da tag
<script> para testar esta unidade.
Opção 2 – Node.js (para exploração extra)
- Mantenha um arquivo
interfaces-excecoes-arquivos.jscom os exemplos. -
No terminal, execute:
node interfaces-excecoes-arquivos.js
1. “Interfaces” em JavaScript
JavaScript não possui a palavra-chave interface como Java, mas
usamos o conceito de interface como um contrato: um conjunto de métodos
que uma função ou classe espera receber. Fazemos isso principalmente com
objetos que seguem um formato (duck typing) ou com classes base.
1.1 Interfaces via duck typing (objeto com formato esperado)
// "Interface" Logger: qualquer objeto que tenha um método log(mensagem)
function processarPedido(pedido, logger) {
// Dependemos apenas de logger.log(...)
logger.log(`Processando pedido ${pedido.id} do cliente ${pedido.cliente}`);
}
// Implementação 1: logger que escreve no console
const ConsoleLogger = {
log(mensagem) {
console.log("[CONSOLE] " + mensagem);
}
};
// Implementação 2: logger que guarda mensagens em memória
const MemoryLogger = {
mensagens: [],
log(mensagem) {
this.mensagens.push(mensagem);
}
};
const pedido = { id: 123, cliente: "Ana" };
processarPedido(pedido, ConsoleLogger);
processarPedido(pedido, MemoryLogger);
console.log("Mensagens em memória:", MemoryLogger.mensagens);
1.2 Interfaces com classes base
// Classe base que funciona como "interface" de pagamento
class Pagamento {
pagar(valor) {
throw new Error("Método pagar(valor) deve ser implementado pela subclasse");
}
}
class PagamentoCartao extends Pagamento {
pagar(valor) {
console.log(`Pagando R$ ${valor} com cartão de crédito`);
}
}
class PagamentoPix extends Pagamento {
pagar(valor) {
console.log(`Pagando R$ ${valor} via PIX`);
}
}
function finalizarCompra(valor, meioPagamento) {
// Aqui dependemos da "interface" Pagamento
meioPagamento.pagar(valor);
}
finalizarCompra(100, new PagamentoCartao());
finalizarCompra(75.5, new PagamentoPix());
Assim como na revisão de OO, usamos herança e sobrescrita de métodos; mas aqui a classe base é pensada como um contrato, e lança erro se alguém esquecer de sobrescrever o método obrigatório.
2. Exceções em JavaScript
Uma exceção é um erro que interrompe o fluxo normal do programa.
Em JavaScript, usamos throw para lançar erros e
try...catch...finally para tratá-los.
2.1 Lançando e tratando erros
function dividir(a, b) {
if (b === 0) {
throw new Error("Divisão por zero não é permitida");
}
return a / b;
}
try {
console.log(dividir(10, 2)); // ok
console.log(dividir(5, 0)); // lança erro
console.log("Esta linha não será executada");
} catch (erro) {
console.error("Ocorreu um erro:", erro.message);
} finally {
console.log("Bloco finally sempre executa (com ou sem erro).");
}
2.2 Exceções para validação de dados
function validarUsuario(usuario) {
if (!usuario.nome) {
throw new Error("Nome é obrigatório");
}
if (!usuario.email || !usuario.email.includes("@")) {
throw new Error("Email inválido");
}
if (usuario.idade < 18) {
throw new Error("Usuário deve ser maior de 18 anos");
}
}
function cadastrarUsuario(usuario) {
try {
validarUsuario(usuario);
console.log("Usuário cadastrado com sucesso:", usuario.nome);
} catch (erro) {
console.error("Erro ao cadastrar usuário:", erro.message);
}
}
cadastrarUsuario({ nome: "João", email: "joao@ifc.edu.br", idade: 20 });
cadastrarUsuario({ nome: "", email: "invalido", idade: 15 });
ValidacaoErro) para diferenciar tipos de falhas,
mas o padrão acima já é suficiente para os exercícios da disciplina.
3. Manipulação de arquivos em JavaScript
A forma de manipular arquivos depende do ambiente onde o JavaScript está rodando:
- Navegador: acesso controlado (upload, download, APIs como
FileReadereBlob). - Node.js: acesso direto ao sistema de arquivos via módulo
fs.
3.1 Lendo um arquivo de texto no navegador
Exemplo de página que permite ao usuário escolher um arquivo .txt
e exibe o conteúdo:
<!-- HTML -->
<input type="file" id="arquivoTexto" accept=".txt">
<pre id="conteudoArquivo"></pre>
<script>
const inputArquivo = document.getElementById("arquivoTexto");
const areaConteudo = document.getElementById("conteudoArquivo");
inputArquivo.addEventListener("change", () => {
const arquivo = inputArquivo.files[0];
if (!arquivo) return;
const leitor = new FileReader();
leitor.onload = () => {
areaConteudo.textContent = leitor.result;
};
leitor.onerror = () => {
console.error("Erro ao ler o arquivo");
};
leitor.readAsText(arquivo, "utf-8");
});
</script>
3.2 Gerando um arquivo para download
<button id="btnSalvar">Baixar relatório</button>
<script>
const botao = document.getElementById("btnSalvar");
botao.addEventListener("click", () => {
const dados = [
"Relatório de vendas",
"-------------------",
"Item A - 10 unidades",
"Item B - 5 unidades"
].join("\n");
const blob = new Blob([dados], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "relatorio.txt";
link.click();
URL.revokeObjectURL(url);
});
</script>
Esse padrão é útil para exportar relatórios, backups simples ou dados de exercícios sem depender de um back-end.
3.3 Visão rápida: arquivos em Node.js
// Exemplo mínimo em Node.js (não roda no navegador)
const fs = require("fs");
// Leitura síncrona
try {
const conteudo = fs.readFileSync("dados.txt", "utf-8");
console.log("Conteúdo do arquivo:", conteudo);
} catch (erro) {
console.error("Erro ao ler arquivo:", erro.message);
}
// Escrita síncrona
try {
fs.writeFileSync("saida.txt", "Nova linha de conteúdo");
console.log("Arquivo salvo com sucesso!");
} catch (erro) {
console.error("Erro ao escrever arquivo:", erro.message);
}
4. Integração: interfaces, exceções e arquivos
Vamos juntar os conceitos em um mini “gerenciador de tarefas”: uma classe base que funciona como interface de repositório, uma implementação em memória e um botão que exporta as tarefas para um arquivo de texto.
de><!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<title>Gerenciador de Tarefas</title>
</head>
<body>
<h3>Gerenciador de tarefas</h3>
<input id="novaTarefa" placeholder="Digite uma tarefa">
<button id="btnAdicionar">Adicionar</button>
<button id="btnExportar">Exportar tarefas</button>
<ul id="listaTarefas"></ul>
<script>
// "Interface" RepositorioTarefas: add(tarefa), listar()
class RepositorioTarefas {
add(tarefa) {
throw new Error("Método add(tarefa) deve ser implementado");
}
listar() {
throw new Error("Método listar() deve ser implementado");
}
}
// Implementação em memória
class RepositorioMemoria extends RepositorioTarefas {
constructor() {
super();
this.tarefas = [];
}
add(tarefa) {
if (!tarefa || tarefa.trim() === "") {
throw new Error("Tarefa não pode ser vazia");
}
this.tarefas.push(tarefa.trim());
}
listar() {
return this.tarefas;
}
}
// Função utilitária para exportar tarefas como arquivo (Blob)
function exportarTarefasComoArquivo(tarefas) {
if (!tarefas.length) {
throw new Error("Não há tarefas para exportar");
}
const conteudo = tarefas.join("\n");
const blob = new Blob([conteudo], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "tarefas.txt";
link.click();
URL.revokeObjectURL(url);
}
// --- Código da interface da página ---
const repo = new RepositorioMemoria();
const input = document.getElementById("novaTarefa");
const btnAdicionar = document.getElementById("btnAdicionar");
const btnExportar = document.getElementById("btnExportar");
const lista = document.getElementById("listaTarefas");
function atualizarLista() {
lista.innerHTML = "";
for (const t of repo.listar()) {
const li = document.createElement("li");
li.textContent = t;
lista.appendChild(li);
}
}
btnAdicionar.addEventListener("click", () => {
try {
repo.add(input.value);
input.value = "";
atualizarLista();
} catch (erro) {
alert("Erro ao adicionar tarefa: " + erro.message);
}
});
btnExportar.addEventListener("click", () => {
try {
exportarTarefasComoArquivo(repo.listar());
} catch (erro) {
alert("Erro ao exportar: " + erro.message);
}
});
</script>
</body>
</html>
5. Exercícios para praticar
Exercício 1 – Calculadora com interface de operação
Descrição:
- Defina uma “interface”
Operacaocom o métodocalcular(a, b). - Implemente
Soma,SubtracaoeMultiplicacaocomo classes concretas. - Crie uma função
executarOperacao(a, b, operacao)que usa o contrato para calcular o resultado. -
No HTML, crie campos para os valores e um
<select>para escolher a operação, exibindo o resultado na página. -
Use
try/catchpara tratar valores inválidos e exibir mensagens amigáveis ao usuário.
Desafio criativo: adicione “Potência” e uma “Divisão segura” que lança exceção se b === 0.
Exercício 2 – Leitor de arquivo CSV simples
Descrição:
- Crie um
<input type="file">que aceite.csv. - Use
FileReader.readAsTextpara ler o arquivo. - Separe linhas com
split("\n")e colunas comsplit(","). - Monte uma tabela HTML (
<table>) para exibir os dados. - Trate erros se o arquivo estiver vazio ou fora do formato esperado.
Desafio criativo: destaque a linha com maior valor em uma coluna numérica (por exemplo, “nota” ou “preço”).
Exercício 3 – “Diário de estudos” com exportação
Descrição:
- Crie um formulário com data, disciplina e resumo do estudo.
-
Defina uma “interface”
RepositorioDiariocomadicionar(registro)elistar(). - Implemente uma versão em memória e exiba os registros em lista ou tabela.
- Adicione um botão “Exportar diário” que gera um
.txtcom todos os registros. - Use exceções para validar: data obrigatória, disciplina não vazia e resumo com tamanho mínimo.
Desafio criativo: crie um filtro para mostrar apenas registros de Programação II.
Exercício 4 – Tratamento de erros de rede (extra)
Descrição:
- Use
fetchpara buscar um JSON em uma API pública de testes. - Implemente uma função
asynccomtry/catchpara tratar erros de rede. - Mostre os dados na página ou, em caso de erro, uma mensagem clara ao usuário.
- Crie uma “interface” para fontes de dados (por exemplo, “API de usuários”, “API de posts”) e duas classes que só mudam a URL.
Roteiro de estudo para quem faltou
- Configure o ambiente (arquivo HTML +
interfaces-excecoes-arquivos.js). - Reproduza e modifique os exemplos de interfaces, exceções e arquivos.
- Implemente pelo menos dois exercícios completos (1, 2 ou 3).
- Liste dúvidas específicas para discutirmos na próxima aula.