Effective Java (Second Edition),第4项,讨论使用私有构造函数来强制执行非实例化。以下是本书中的代码示例:
public final class UtilityClass {
private UtilityClass() {
throw new AssertionError();
}
}
然而,AssertionError
似乎不合适。没有任何东西被“断言”,这就是API如何定义AssertionError的使用。
在这种情况下,通常会有不同的Throwable
吗?通常只会向一般Exception
发送一条消息吗?或者为此编写自定义Exception
是常见的吗?
这是非常微不足道的,但我认为从形式和标准的角度来看,我只是对此感到好奇。
答案 0 :(得分:28)
有一个断言:“我断言这个构造函数永远不会被调用”。所以,确实AssertionError
在这里是正确的。
答案 1 :(得分:10)
我喜欢包括Bloch的评论:
// Suppress default constructor for noninstantiability
或者更好的是把它放在错误中:
private UtilityClass()
{
throw new AssertionError("Suppress default constructor for noninstantiability");
}
答案 2 :(得分:3)
UnsupportedOperationException听起来最合适,但检查异常会更好,因为它可能会警告某人在编译时错误地实例化该类。
答案 3 :(得分:2)
IllegalAcessError怎么样? :)
答案 4 :(得分:2)
不不不,对Josh Bloch充满敬意,永远不会抛出AssertionError
,除非它来自断言。如果你想在这里使用AssertionError,请将其抛出{{1} }。那么阅读代码的人可以在以后找到它。
更好的是,定义自己的例外,比如assert(false)
。然后你会有代码
CantInstantiateUtilityClass
以便捕手的读者知道发生了什么。
<强>更新强>
每隔一段时间,一些该死的傻瓜就会在这里徘徊,并在事实发生近四年之后再次投票。所以,我要注意标准仍然定义try {
// some stuff
} catch (CantInstantiateUtilityClass e) {
// react
}
作为断言失败的结果,而不是一些初学者认为应该被抛出的地方一个明确定义的信息例外。遗憾的是,良好的异常规则可能是Java编程中最不受鼓励的技能。
答案 5 :(得分:1)
当代码要求将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.");
}
答案 6 :(得分:0)
断言断言意味着您违反了代码的合同规范。所以这是正确的。
但是,我假设你将私下实例化一个实例,它也会调用构造函数并导致错误 - 除非你有另一个构造函数?
答案 7 :(得分:0)
您可以创建自己的扩展Throwable
的类,例如:
class NoninstantiabilityError extends Throwable
这具有以下优点:
Throwable
,因此不太可能被偶然捕获Throwable
,因此它被检查,并且偶然调用相应的构造函数将需要捕获异常用法示例:
public final class UtilityClass {
private UtilityClass() throws NoninstantiabilityError {
throw new NoninstantiabilityError();
}
...
}