Usar try/finally e try/except com responsabilidades diferentes
Tutorial · prática orientada · FundamentosFunções, objetos e leitura de arquivos
Unit principal compilada e exercitada com DCC32 37.0, build 37.0.59082.6021. Referência editorial: Delphi 11.3 e 13.2; essas duas versões não foram verificadas individualmente.Documentação, instalação e limites de Fundamentos em seis units
Imagine que um relatório abre um arquivo, processa seu conteúdo e falha na metade. Há duas necessidades distintas: liberar o arquivo e decidir o que fazer com o erro. Misturar essas responsabilidades produz código que parece protegido, mas perde o diagnóstico ou mantém recursos abertos.
Neste artigo, vamos usar uma leitura simples para reconhecer essas fronteiras. A lição vale também para objetos temporários, consultas e integrações.
Limpeza não é recuperação
try/finally executa a limpeza ao sair do bloco protegido. try/except trata uma exceção. Um finally não transforma uma operação que falhou em sucesso. Um except que não faz nada pode esconder a falha. A descrição da linguagem está em Exceptions (Delphi).
Por isso, pergunte primeiro: este bloco protege um recurso ou representa uma decisão de recuperação? A resposta define a estrutura.
Proteja a duração do objeto
Crie Arquivos.Texto.pas:
unit Arquivos.Texto;
interface
function LerTexto(const Caminho: string): string;
implementation
uses
System.Classes, System.SysUtils;
function LerTexto(const Caminho: string): string;
var
Linhas: TStringList;
begin
Linhas := TStringList.Create;
try
Linhas.LoadFromFile(Caminho, TEncoding.UTF8);
Result := Linhas.Text;
finally
Linhas.Free;
end;
end;
end.O objeto é criado antes do try. Se o construtor falhar, não existe uma instância válida para liberar nesse bloco. Depois da criação, a leitura e a atribuição ficam protegidas.
Essa função preserva a exceção da leitura. Ela não consegue decidir se o usuário deve escolher outro arquivo, se o processo deve parar ou se uma rotina automática deve registrar a falha. Essas decisões pertencem ao chamador.
Capture na fronteira que consegue agir
Um consumidor pode informar que a leitura falhou ou registrar detalhes para diagnóstico. Se não puder recuperar a operação, relance a exceção em vez de devolver texto vazio como se ele fosse o conteúdo do arquivo.
try
Conteudo := LerTexto(Caminho);
except
on E: Exception do
begin
// Registrar diagnóstico conforme a política da aplicação.
raise;
end;
end;O trecho pressupõe Conteudo e Caminho como strings e System.SysUtils no escopo. Aqui, raise; relança a exceção ativa. O comentário não é uma implementação de log: não use esse trecho como prova de que o erro foi registrado.
Não capture uma exceção apenas para repetir a mesma mensagem em outra Exception. Você pode perder informações úteis sobre a origem. Se houver tradução para uma falha de aplicação, preserve o contexto em um mecanismo de diagnóstico definido.
Validação esperada pode ter outro caminho
Um campo vazio informado pelo usuário não precisa sempre gerar uma exceção. Uma função de validação pode devolver um resultado com os problemas encontrados. Exceções são adequadas quando o contrato precisa interromper a operação ou quando uma dependência já sinaliza falha dessa maneira.
Consistência importa mais que uma regra absoluta. Não misture, sem explicar, False, string vazia e exceção para representar o mesmo erro.
Cuidado com o próprio tratamento
O código de limpeza e de diagnóstico também pode falhar. Evite colocar operações frágeis dentro do finally, especialmente se elas podem mascarar uma falha já em andamento. Liberar um recurso e enviar um log remoto não têm a mesma urgência nem a mesma confiabilidade.
Em tarefas de fundo, o tratamento deve considerar como o erro volta ao consumidor. Uma exceção fora da thread da interface não equivale automaticamente a uma mensagem visível ao usuário.
Roteiro de verificação
Teste arquivo existente, arquivo ausente, acesso negado e conteúdo UTF-8. Verifique que o chamador diferencia arquivo vazio de leitura que falhou. Se sua aplicação recebe caminhos externos, valide também o diretório permitido antes de acessar o disco.
A unit LerTexto foi compilada e verificada com arquivo UTF-8, vazio e ausente. O trecho de tratamento no chamador continua sendo um exemplo de integração. A próxima leitura conecta esse cuidado ao trabalho assíncrono: Tarefas sem travar a interface.
Runner seguro: UTF-8, vazio e ausente
Antes, o runner usava nome fixo no diretório corrente. A nova revisão usa pasta temporária exclusiva com GUID e limpa somente recursos próprios.
- Crie texto-teste.txt com conteúdo conhecido na pasta corrente.
- Compile VerificarExemplos.dpr da nova revisão e execute.
- Confira UTF-8, vazio e ausência; ausência gera erro esperado, não string vazia silenciosa.
- Compare o arquivo preexistente byte a byte.
Em 08/10/2026, as 32 verificações passaram e o arquivo preexistente foi preservado. Relatório. O pacote legado permanece; prefira a revisão segura. finally libera; except trata na fronteira capaz de agir.