tipos - todas las excepciones en java
¿Cómo no lanzar una excepción genéricamente especificada? (6)
Creé una interfaz de "productor" (para ser utilizada con referencias de métodos, respectivamente para ser fácilmente burlada para pruebas unitarias):
@FunctionalInterface
public interface Factory<R, T, X extends Throwable> {
public R newInstanceFor(T t) throws X;
}
que creé así, ya que mi primer caso de uso en realidad tuvo que arrojar algunos WhateverException
verificados.
Pero mi segundo caso de uso no tiene una X para lanzar.
Lo mejor que se me ocurrió para hacer feliz al compilador es:
Factory<SomeResultClass, SomeParameterClass, RuntimeException> factory;
Eso compila, y hace lo que necesito, pero sigue siendo feo. ¿Hay una manera de mantener esa interfaz única, pero no proporcionar una X al declarar instancias específicas?
¿Tienes que hacer la excepción genérica? ¿Por qué no definir la interfaz como
@FunctionalInterface
public interface Factory<R, T> {
public R newInstanceFor(T t) throws Throwable;
}
Siempre puede detectar su excepción y verificar el tipo si necesita la función de llamada.
Esta es más una respuesta de "ingeniería social": colocamos un contrato en la forma lambda que no arroja nada:
public interface Factory<T, R, X> {
public R newInstanceFor(T arg) throws X;
public static Factory<R, U, AssertionError> neverThrows(Factory<U, V, ?> input) {
return u -> {
try {
return input.newInstanceFor(u);
}
catch(Throwable t) {
throw new AssertionError("Broken contract: exception thrown", t);
}
};
}
}
El uso es así, o algo parecido a:
class MyClass {
Factory<MyInput, MyOtherClass, AssertionError> factory;
MyClass(Factory<MyInput, MyOtherClass, ?> factory) {
this.factory = Factory.neverThrows(factory);
}
public void do() {
factory.newInstanceFor(new MyInput()).do();
}
}
La desventaja de este enfoque: realmente no puede especificar el contrato en la firma de tipo, el contrato es un detalle de implementación. Si desea tener este tipo de firma, necesitará una segunda sub-interfaz.
La única forma de hacerlo es crear subclases, pero apuesto a que lo sabías. Para fortalecer mi argumento, mire BinaryOperator
que extiende BiFunction
.
No puedes hacer eso en Java. La única forma es crear una sub-interfaz.
public interface DefaultExceptionFactory<R, T>
extends Factory<R, T, RuntimeException>
Puede definir el método como código genérico a continuación, si es posible para usted:
@FunctionalInterface
public interface Factory<R, T> {
public <X extends Throwable> R newInstanceFor(T t) throws X;
}
Puede usar la anotación @SneakyThrows Proyecto Lombok :
@FunctionalInterface
public interface Factory<R, T> {
@SneakyThrows
R newInstanceFor(T t);
}
Esto le permite lanzar cualquier excepción (activada o desactivada). Pero lea la documentación porque esta característica debe manejarse con cuidado.