style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

Odio las excepciones verificadas

De verdad que deberían haber eliminado por completo las excepciones verificadas para Java 8. Estorban. No es una coincidencia que casi todos los demás lenguajes de la JVM las eliminaron.

BEGIN RANT

Tengo una clase donde implemento un método abstracto más o menos así:

@Override
protected Runnable crearTarea(Request req) {
  Response resp = new Respuesta(Errores.CANT_CONNECT);
  if (req.getTipo() == Request.UnaCosa) {
    return () -> {
      try {
        unaCosa(req, resp);
      } catch (IOException ex) {
        log.error("Haciendo una cosa con {}", req, ex);
      } finally {
        procesaRespuesta(resp);
      }
    };
  } else if (req.getTipo() == Request.OtraCosa) {
    return () -> {
      try {
        otraCosa(req, resp);
      } catch (IOException ex) {
        log.error("Haciendo otra cosa con {}", req, ex);
      } finally {
        procesaRespuesta(resp);
      }
    };
  } else if (req.getTipo() == Request.OoootraCosa) {
    return () -> {
      try {
        oootraCosa(req, resp);
      } catch (IOException ex) {
        log.error("Haciendo todavía otra cosa con {}", req, ex);
      } finally {
        procesaRespuesta(resp);
      }
    };
  }
  return null;
}

Como pueden ver, se repite mucho código. Así que tuve la grandiosa idea de ponerlo en otro método y evitarme tantas broncas, y quedar con algo así:

private Runnable ejecutar(BiConsumer<Request, Response> m,
        Request req, Response resp, String mensaje) {
  return () -> {
    try {
      m.accept(req, resp);
    } catch (IOException ex) {
      log.error(mensaje, ex);
    } finally {
      procesaRespuesta(resp);
    }
  };
}

@Override
public Runnable crearTarea(Request req) {
  Response resp = new Respuesta(Errores.CANT_CONNECT);
  if (req.getTipo() == Request.UnaCosa) {
    return ejecutar(this::unaCosa, req, resp, "Haciendo una cosa con {}");
  } else if (req.getTipo() == Request.OtraCosa) {
    return ejecutar(this::otraCosa, req, resp, "Haciendo otra cosa con {}");
  } else if (req.getTipo() == Request.OoootraCosa) {
    return ejecutar(this::oootraCosa, req, resp, "Haciendo oootra cosa con {}");
  }
  return null;
}

Se ve mucho más bonito, ¿no?

Pues no se puede. Porque BiConsumer no arroja IOException y por lo tanto no la puedo cachar. Tendría que cacharla en cada uno de mis métodos que la arrojan, sólo para convertirla en una excepción de tiempo de ejecución que sí pudiera cachar en ejecutar.

Así no se pinches puede. Ni modo... ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z ⌘+Z

END RANT

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

Solución

Publiqué esto mismo en dev.to y alguien me dio una solución que funcionó muy bien: crear una interfaz funcional que declare la excepción. Es un poco engorroso pero pues:

@FunctionalInterface
private interface Tarea {
  void correr(Request req, Response resp) throws IOException;
}

Y modificar el método ejecutar para que reciba esta interfaz. Lo demás queda igual y entonces ahora sí ya se puede.

Por cierto dejé un bug en este código: el log debería ser log.error(mensaje, req, ex).

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">