¿Cuál es el Throwable preferido para usar en un constructor de la clase utilidad privada?
-
29-08-2019 - |
Pregunta
Effective Java (Segunda Edición) , punto 4, discute el uso de constructores privados a cumplir noninstantiability. Aquí está el ejemplo de código del libro:
public final class UtilityClass {
private UtilityClass() {
throw new AssertionError();
}
}
Sin embargo, AssertionError
no parece ser lo correcto para lanzar. Nada está siendo "afirmado", que es como la API define el uso de AssertionError .
¿Hay una Throwable
diferente que es típicamente en esta situación? ¿Uno por lo general sólo un tiro de un Exception
general, con un mensaje? O es común escribir un Exception
personalizado para esto?
Es bastante trivial, pero más que nada supongo que soy sólo curiosidad al respecto desde una perspectiva de estilo y estándares.
Solución
Hay una afirmación: "Estoy afirmando que este constructor no se llamará". Así que, de hecho, AssertionError
es correcto en este caso.
Otros consejos
Me gusta que incluye el comentario de Bloch:
// Suppress default constructor for noninstantiability
O todavía mejor ponerlo en el error:
private UtilityClass()
{
throw new AssertionError("Suppress default constructor for noninstantiability");
}
UnsupportedOperationException suena como la mejor en forma, a través de una excepción comprobada sería aún mejor, ya que podría advertir a alguien erróneamente crear instancias de la clase en tiempo de compilación.
¿Qué hay de IllegalAcessError ? :)
No no no, con el debido respeto a Josh Bloch, Nunca arroje un AssertionError
a menos que sea a partir de una afirmación. Si desea una AssertionError aquí, a la basura con assert(false)
. Entonces alguien que lee el código puede encontrarlo más tarde.
Aún mejor, definir su propia excepción, dicen CantInstantiateUtilityClass
. entonces tendrá código que dice
try {
// some stuff
} catch (CantInstantiateUtilityClass e) {
// react
}
para que el lector del receptor sabe lo sucedió.
Actualizar
De vez en cuando algún idiota se pasea por aquí y downvotes esto otra vez, casi cuatro años después del hecho. Por lo tanto, permítanme señalar que la norma Todavía define AssertionError
como el resultado de una aserción fallida, no como lo que piense un poco de principiante debéis para ser lanzado en lugar de un bien excepción informativa definida. Lamentablemente, una buena disciplina excepción es quizás la habilidad menos alentado en programación Java.
Cuando el código requiere la inclusión de la JUnit como una dependencia tal como dentro del alcance <scope>test</scope>
prueba experto, a continuación, ir directamente a Assertion.fail()
método y beneficiarse de una mejora significativa en la claridad.
public final class UtilityClass {
private UtilityClass() {
fail("The UtilityClass methods should be accessed statically");
}
}
Cuando esté fuera del alcance de prueba, usted podría utilizar algo como lo siguiente, lo que requeriría una importación estática para el uso como la de arriba. import static pkg.Error.fail;
public class Error {
private static final Logger LOG = LoggerFactory.getLogger(Error.class);
public static void fail(final String message) {
LOG.error(message);
throw new AssertionError(message);
// or use your preferred exception
// e.g InstantiationException
}
}
Lo que el siguiente uso.
public class UtilityClassTwo {
private UtilityClassTwo() {
Error.fail("The UtilityClass methods should be accessed statically");
}
}
En su forma más idiomática, todas se reducen a esto:
public class UtilityClassThree {
private UtilityClassThree() {
assert false : "The UtilityClass methods should be accessed statically";
}
}
Uno de los incorporados en las excepciones, UnsupportedOperationException puede ser arrojado a indican que 'la operación solicitada no es compatible'.
private Constructor() {
throw new UnsupportedOperationException(
"Do not instantiate this class, use statically.");
}
Una afirmación rota significa que usted ha roto una especificación del contrato de su código. Por lo que es lo correcto.
Sin embargo, como supongo podrás crear instancias de una instancia privada, sino que también llamar al constructor de errores y causar una menos que tenga otro constructor?
Usted puede crear su propia Throwable
extender la clase, por ejemplo:.
class NoninstantiabilityError extends Throwable
Esto tiene las siguientes ventajas:
- El nombre indica que el problema
- Debido a que se extiende directamente
Throwable
es poco probable que será capturado por accidente - Debido a que se extiende directamente
Throwable
se comprueba y llamando al constructor respectiva por accidente requeriría agarrar la excepción
Ejemplo de uso:
public final class UtilityClass {
private UtilityClass() throws NoninstantiabilityError {
throw new NoninstantiabilityError();
}
...
}