Jerarquía de excepciones MultagalException
Diseñar e implementar la jerarquía de excepciones propia del proyecto, sustituyendo en A1.1, A1.2 y A1.3 la propagación directa de excepciones de bajo nivel (IOException y afines) por excepciones expresadas en el lenguaje del dominio.
1Comprobadas vs. no comprobadas
Antes de diseñar la jerarquía, ten clara la diferencia: define si MultagalException obligará al llamador a capturarla o no.
| Aspecto | Comprobadas (checked) | No comprobadas (unchecked) |
|---|---|---|
| Superclase | Exception (salvo RuntimeException) | RuntimeException |
| Obligación del compilador | Capturar o declarar con throws | Opcional |
| Caso típico en E/S | IOException, NoSuchFileException | NullPointerException, IllegalArgumentException |
| Uso habitual | Errores recuperables externos | Errores de programación / de dominio ya traducidos |
2Subtipos de dominio
Al menos una excepción para «no encontrado» y otra para fallos de almacenamiento — las que ya necesitan A1.1 y A1.2.
public class MultagalException extends RuntimeException {
public MultagalException(String mensaje, Throwable causa) {
super(mensaje, causa);
}
}
public class ExpedienteNoEncontradoException extends MultagalException {
public ExpedienteNoEncontradoException(String numero, Throwable causa) {
super("No existe el expediente: " + numero, causa);
}
}
public class AlmacenamientoException extends MultagalException {
public AlmacenamientoException(String mensaje, Throwable causa) {
super(mensaje, causa);
}
}
3Traducir las excepciones de bajo nivel
Revisa el código de A1.1 (AlmacenExpedientes), A1.2 (ServicioPurgaExpedientes) y A1.3 (VigilanteBuzonEntrada): ningún método público debe dejar escapar IOException sin traducir.
public Optional<Path> buscar(String numeroExpediente) {
try (Stream<Path> stream = Files.walk(raiz)) {
return stream
.filter(Files::isRegularFile)
.filter(p -> coincide(p, numeroExpediente))
.findFirst();
} catch (IOException e) {
throw new AlmacenamientoException(
"Error de E/S al buscar el expediente " + numeroExpediente, e);
}
}
causa) al construir la excepción de dominio: sin ella se pierde la traza real del fallo en producción.4try-with-resources en todo recurso AutoCloseable
Aprovecha la revisión para confirmar que todo Stream<Path>, WatchService u otro recurso cerrable de A1.1–A1.3 usa try-with-resources y no un finally manual.
// Varios recursos: se cierran en orden inverso, incluso si hay excepción
try (Stream<Path> stream = Files.walk(raiz);
WatchService watcher = FileSystems.getDefault().newWatchService()) {
// ...
}
5Diario técnico
Justifica por escrito por qué la raíz de la jerarquía es no comprobada.
!Problemas frecuentes
new AlmacenamientoException("fallo")) sin pasar la IOException original como causa deja el stacktrace inútil para depurar en producción.Exception en vez del tipo concreto (IOException, NoSuchFileException...) esconde bugs de programación bajo la misma traducción que los errores de E/S reales.✓Criterios de aceptación
MultagalExceptionextiendeRuntimeException- Cada excepción de dominio conserva la excepción original como causa
- Ningún método público de A1.1–A1.3 deja escapar
IOExceptionsin traducir - Todo recurso
AutoCloseableusatry-with-resources - El diario técnico justifica por qué la raíz es no comprobada
Adaptado de apartado f — Excepciones y configuración y apartado h — Actividades.