Pular para o conteúdo principal

Tratamento de Erros

Os mecanismos de tratamento de erros variam significativamente entre as linguagens. Veja como diferentes linguagens lidam com erros e exceções.

Tratamento Básico de Erros​

// Try-catch
try {
riskyOperation();
} catch (error) {
console.error("Error:", error.message);
} finally {
cleanup();
}

// Throwing errors
throw new Error("Something went wrong");

// Custom errors
class CustomError extends Error {
constructor(message) {
super(message);
this.name = "CustomError";
}
}

Padrões Avançados de Tratamento de Erros​

// Promise error handling
fetch('/api/data')
.then(response => response.json())
.catch(error => console.error("Error:", error));

// Async/await
async function fetchData() {
try {
const response = await fetch('/api/data');
return await response.json();
} catch (error) {
console.error("Error:", error);
throw error;
}
}

// Error boundaries (React)
class ErrorBoundary extends React.Component {
componentDidCatch(error, errorInfo) {
logErrorToService(error, errorInfo);
}
}

Principais Conclusões​

  • Exceções vs retorno de erros -- JavaScript, Python, PHP, Ruby, Java, C#, C++ e Swift usam exceções no estilo try/catch: você throw ou raise e opcionalmente catch adiante. Go e Zig usam retorno explícito de erros: result, err := divide(10, 2) em Go e const result = divide(10, 2) catch |err| { ... } em Zig. Rust usa Result<T, E> e Option<T> no sistema de tipos. C usa códigos de retorno (int divide(..., double* result) retornando 0 ou -1) e errno. Exceções permitem que erros se propaguem implicitamente pela pilha de chamadas; retorno de erros força cada ponto de chamada a decidir. Escolha exceções quando quiser tratamento centralizado; escolha retorno de erros quando quiser fluxo de controle explícito e menos surpresas.

  • Tipos Result/Option -- Result<T, E> do Rust e as uniões de erro !T do Zig codificam erros no sistema de tipos. Por exemplo, fn divide(a: f64, b: f64) -> Result<f64, String> em Rust força os chamadores a tratar Ok e Err via match, ? ou .unwrap(). O fn divide(a: f64, b: f64) !f64 do Zig retorna um valor ou um erro de um conjunto de erros em tempo de compilação. O Result<String, NetworkError> do Swift é opcional, mas comum para código assíncrono. O (value, error) do Go é idiomático e verificado com if err != nil. Tipos Result tornam "isto pode falhar" visível nas assinaturas. Prefira Rust ou Zig quando quiser garantias em tempo de compilação de que os erros são tratados.

  • Tratamento obrigatório pelo compilador -- Rust e Zig exigem tratamento explícito de erros: você deve usar match, ?, try ou catch, ou o código não compilará. Por exemplo, let contents = File::open(path)?; em Rust propaga erros; ignorar o ? exigiria unwrap() ou expect(), que é explícito. Em Python, Java ou JavaScript, você pode chamar uma função que lança exceção sem try/catch e o erro se propagará (ou causará crash) silenciosamente até ser capturado. Se sua prioridade é eliminar erros não tratados em tempo de compilação, escolha Rust ou Zig; se preferir flexibilidade e handlers centralizados, use linguagens baseadas em exceções.

  • Propagação e encapsulamento de erros -- Go 1.13+ suporta fmt.Errorf("failed: %w", err) para encapsulamento e errors.Is(err, ErrNotFound) para verificação. O operador ? do Rust propaga erros preservando a conversão via From. Python usa raise RuntimeError("failed") from e para encadeamento. Java e C# suportam encadeamento de exceções com initCause. O encapsulamento preserva o contexto quando erros borbulham para cima. Escolha linguagens com bom suporte a encapsulamento ao construir sistemas em camadas onde erros atravessam muitas fronteiras.

  • Limpeza de recursos -- RAII (C++), defer (Go, Zig), using (C#), try-with-resources (Java) e with (Python) garantem limpeza mesmo quando erros ocorrem. Por exemplo, defer file.close() do Zig e using var file = new FileStream(...) do C# garantem a liberação. C não possui mecanismo embutido; você deve usar goto cleanup ou condicionais aninhados. Prefira linguagens com limpeza estruturada ao gerenciar arquivos, conexões ou locks para evitar vazamentos em caminhos de erro.