在私有实用程序类构造函数中使用的首选Throwable是什么?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在私有实用程序类构造函数中使用的首选Throwable是什么?相关的知识,希望对你有一定的参考价值。
Effective Java (Second Edition),第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
定义为断言失败的结果,而不是某些初学者认为应该抛出一个明确定义的信息异常。遗憾的是,良好的异常规则可能是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();
}
...
}
以上是关于在私有实用程序类构造函数中使用的首选Throwable是什么?的主要内容,如果未能解决你的问题,请参考以下文章