[英]Is it mandatory utility class should be final and private constructor?
[英]What is the preferred Throwable to use in a private utility class constructor?
Effective Java(第二版)第 4 项讨论了使用私有构造函数来强制不可实例化。 这是书中的代码示例:
public final class UtilityClass {
private UtilityClass() {
throw new AssertionError();
}
}
但是, AssertionError
似乎不适合抛出。 没有任何东西被“断言”,这就是 API 定义AssertionError使用的方式。
在这种情况下是否有不同的Throwable
? 是否通常只是抛出一个带有消息的一般Exception
? 或者为此编写自定义Exception
是否常见?
这很微不足道,但最重要的是,我想我只是从风格和标准的角度对它感到好奇。
有一个断言:“我断言这个构造函数永远不会被调用”。 所以,确实, AssertionError
在这里是正确的。
我喜欢包括 Bloch 的评论:
// Suppress default constructor for noninstantiability
或者更好的是把它放在错误中:
private UtilityClass()
{
throw new AssertionError("Suppress default constructor for noninstantiability");
}
UnsupportedOperationException听起来是最合适的,尽管检查异常会更好,因为它可能会警告某人在编译时错误地实例化类。
IllegalAcessError呢? :)
不不不,出于对 Josh Bloch 的尊重,永远不要抛出AssertionError
除非它来自断言。 如果你想要一个 AssertionError 在这里,用assert(false)
抛出它。 然后有人阅读代码可以稍后找到它。
更好的是,定义你自己的异常,比如CantInstantiateUtilityClass
。 然后你会有代码说
try {
// some stuff
} catch (CantInstantiateUtilityClass e) {
// react
}
以便捕手的读者知道发生了什么。
让我注意到,标准仍然将AssertionError
定义为AssertionError
失败的结果,而不是一些初学者认为应该抛出的东西来代替定义明确的信息异常。 遗憾的是,良好的异常纪律可能是 Java 编程中最不鼓励的技能。
当代码需要包含 JUnit 作为依赖项时,例如在 maven 测试范围<scope>test</scope>
,然后直接转到Assertion.fail()
方法并受益于清晰度的显着改进。
public final class UtilityClass {
private UtilityClass() {
fail("The UtilityClass methods should be accessed statically");
}
}
在测试范围之外时,您可以使用如下所示的内容,这需要静态导入才能使用。 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
}
}
有以下用法。
public class UtilityClassTwo {
private UtilityClassTwo() {
Error.fail("The UtilityClass methods should be accessed statically");
}
}
以其最惯用的形式,它们都归结为:
public class UtilityClassThree {
private UtilityClassThree() {
assert false : "The UtilityClass methods should be accessed statically";
}
}
作为内置异常之一,可以抛出 UnsupportedOperationException 以指示“不支持请求的操作”。
private Constructor() {
throw new UnsupportedOperationException(
"Do not instantiate this class, use statically.");
}
断言断言意味着您已经破坏了代码的契约规范。 所以这是正确的事情。
但是,正如我假设您将私下实例化一个实例,它也会调用构造函数并导致错误 - 除非您有另一个构造函数?
您可以创建自己的类扩展Throwable
,例如:
class NoninstantiabilityError extends Throwable
这具有以下优点:
Throwable
所以不太可能会被意外抓住Throwable
它被检查并且意外调用相应的构造函数将需要捕获异常用法示例:
public final class UtilityClass {
private UtilityClass() throws NoninstantiabilityError {
throw new NoninstantiabilityError();
}
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.