Si NULL es el desacierto del billón de dólares
¿una mala estrategia de manejo de errores qué sería?
https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/One_Ring_Blender_Render.png/250px-One_Ring_Blender_Render.png
try {
// código
try {
// código
} catch() {
// código
}
} catch () {
// código
}
try {
// código
} catch () {
// código
try {
// código
} catch() {
// código
}
}
// código
try {
// código
} catch () {
// código
}
// código
try {
// código
} catch() {
// código
}
// código
public T foo(...) {
try { // nada antes de try
// algoritmo a ejecutar
} catch(...) { // x n
// manejo de errores
} // nada después del último catch
}
public T foo(...) {
try {
doFoo(...);
} catch(...) { // x n
// manejo de errores
}
}
private T doFoo(...) {
// código solo con
// reglas de negocio
}
public Fracción(int numerador, int denominador) {
if (denominador == 0) {
var mensaje = "Denominador no puede ser cero";
throw new IllegalArgumentException(mensaje);
}
}
T foo(Theaker theaker, Withms withms, Cheedy cheedy) {
if (theaker ...) {
var mensaje = ...;
throw new IllegalArgumentException(mensaje);
}
if (withms ...) {
var mensaje = ...;
throw new IllegalArgumentException(mensaje);
}
if (cheedy ...) {
var mensaje = ...;
throw new IllegalArgumentException(mensaje);
}
// ¡por fin, código!
}
public Fracción(int numerador, int denominador) {
Precondiciones.vericar(numerador != 0, "Numerador no puede ser 0");
// código
}
T foo(Theaker theaker, Withms withms, Cheedy cheedy) {
Precondiciones.verificar(theaker ..., "");
Precondiciones.verificar(withms ..., "");
Precondiciones.verificar(cheedy ..., "");
// ¡por fin, código!
}
T foo(Theaker theaker, Withms withms, Cheedy cheedy) {
verificarPrecondiciones(theaker, withms, cheedy);
// código
}
private static void verificarPrecondiciones(...) {
Precondiciones.verificar(theaker ..., "");
Precondiciones.verificar(withms ..., "");
Precondiciones.verificar(cheedy ..., "");
}
public static void verificarNoNulo(Object obj) {
if (obj == null) {
throw new IllegalArgumentException("...");
}
}
public <T> static void verificarListaNoVacía(List<T> list) {
verificarNoNulo(list);
if (list.isEmpty()) {
throw new IllegalArgumentException("...");
}
}
public <T> static void listaIniciaConMarcador(List<String> list) {
verificarListaNoVacía(list);
if (!list.get(0).equals(">>>")) {
throw new IllegalArgumentException("...");
}
}
public class Andinar(Moslaves moslaves, Seledge seledge) {
this.moslaves = Objects.requireNonNull(moslaves, "...");
this.seledge = Objects.requireNonNull(seledge, "...");
}
public static void foo(String s) {
if (s == null) {
s = "{}"; // valor por defecto
}
// más código
}
* * *
var miEse = bar(); // por un error es null!
foo(miEse); // el método no falla
// silenciamos el error!
public static void foo(String s) {
Objects.requiereNonNull(s, "...");
// más código
}
public static void foo() {
return foo("{}");
}
* * *
var miEse = bar(); // por un error es null
foo(miEse); // excepción lanzada
"La transacción por $X no tiene fondos suficientes en la tarjeta ACME terminada en 1234. Mensaje original: ..."
public class Transacción {
private BigDecimal monto;
private Tarjeta tarjeta;
// más atributos
public String toString() {
return "Transacción[monto=" + monto + ",tarjeta=" + tarjeta + "]";
}
}
* * *
var mensaje = "Fondos Insuficientes. Estado de la transacción "
+ transacción + ". Error original: " + e.getMessage();
try {
var sunnota = new Sunnota(o);
var befals = sunnota.getBefals();
var vation = befals.getVation();
var sovely = new Sovely(ot);
return soverly.freages();;
} catch (Exception e) {
// 🤔
// ¿Cuáles excepciones son realmente esperadas?
// ¿Cuáles excepciones nos sorprenderían?
}
try {
var sunnota = new Sunnota(o);
var befals = getBefals(sunnota); // ACMEException
var vation = befals.getVation();
var sovely = new Sovely(ot);
return soverly.freages(); // A113Exception
} catch (AcmeException e) {
// ¡no hay donde esconderse!
} catch (A113Exception e) {
// ¡no hay donde esconderse!
}
try {
var sunnota = new Sunnota(o);
var befals = getBefals(sunnota); // ACMEException
var vation = befals.getVation(); // THXException
var sovely = new Sovely(ot);
return soverly.freages(); // A113Exception
} catch (AcmeException e) { // NO compila no manejamos THXException
} catch (A113Exception e) {
}
} catch (ACMEException | A113Exception e) {
// no hay repetición de código
}
private T foo(...) {
var baz = null;
try {
// código
} catch(...) {
// manejo de errores
}
return baz; // 😟
}
private T foo(...) {
try {
var baz = ...;
// código
return baz;
} catch(...) {
// manejo de error
return null;
}
}
public Optional<T> foo(...) {
try {
var baz = ...;
// código
return Optional.of(baz);
} catch(...) {
// manejo de error
return Optional.empty();
}
}
public T foo(...) {
// código
var matchip = ...; // tenemos un Matchip
var declain = ...; // tenemos un Declain
return doFoo(matchip, declain);
}
private T doFoo(Matchip matchip, Declain declain) {
try {
// código que usa
// matchip y declain
} catch (ACMEException e) {
log.error(...); // algo con matchip y declain
}
}
public class UsuarioDAO {
// más código
public Usuario porId() throws PersistenceException {
try {
// código
} catch (SQLException e) {
throw new PersistenceException(e);
}
}
}
public void foo() throws ACMEException {
try {
// código
} catch (ACMEException e) {
// info solo disponible en este método
log.trace(...);
throw e;
}
}
* * *
try {
// código
foo();
// código
} catch (ACMEException e) {
// todo el resto de la información
log.trace(...);
}
try {
} catch (ACMEException e) {
// toda la información va en el mensaje!
var mensaje = ... + monto + ...
+ tarjeta.últimos4Dígitos() + ... + e.getMessage();
throw new TransactionException(mensaje); // 😮
}
public class TransacciónExcepción extends Exception {
private BigDecimal monto;
private String últimos4Dígitos;
public TransacciónExcepción(BigDecimal monto, String últimos4Dígitos, ACMEException e) {
super(origin);
this.monto = monto;
this.últimos4Dígitos = últimos4Dígitos;
}
public BigDecimal monto() {
return monto;
}
public String últimos4Dígitos() {
return últimos4Dígitos;
}
}
* * *
try {
// código
} catch (TransacciónException e) {
var monto = e.getMonto();
var últimos4Dígitos = e.getÚltimos4Dígitos();
var mensajeOriginal = e.getCause().getMessage();
// mensaje en cualquier idioma, fácil de cambiar
}
public void foo(...) throws IOException {}
public void bar(...) throws IOException {}
public void baz(...) throws IOException {
foo(); // ¿cómo manejo este error ...
bar(); // ... sin mezclarlo con este?
}
public void foo(...) throws IOException {}
public void bar(...) throws WrappedException {
try {
// código
} catch (IOException e) {
throw new WrappedException(e);
}
}
public void baz(...) throws WrappedException, IOException {
foo(); // catch IOException
bar(); // catch WrappedException
}
try (var fileInpuStream =
new FileInputStream("/path/al/archivo");
// utiliza fileInputStream
}
public static void main(String[] args) {
try (var hal = new Hal9000();
var p2501 = new Project2501(hal)) {
// código que no imprime nada
} // close() se llama en este punto
}
static class Hal9000 implements AutoCloseable {
public void close() throws RuntimeException {
System.out.println("Ciao Hal");
}
}
static class Project2501 implements AutoCloseable {
Project2501(Hal9000 hal) {}
public void close() throws RuntimeException {
System.out.println("Ciao 2501");
throw new RuntimeException("😔");
}
}