Carlos Obregón
Java Champion with 15 years of experience in software programming
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("😔");
}
}
By Carlos Obregón