在私有实用程序类构造函数中使用的首选Throwable是什么?

时间:2008-12-29 22:44:11

标签: java coding-style throwable

Effective Java (Second Edition),第4项,讨论使用私有构造函数来强制执行非实例化。以下是本书中的代码示例:

public final class UtilityClass {
    private UtilityClass() {
        throw new AssertionError();
    }
}

然而,AssertionError似乎不合适。没有任何东西被“断言”,这就是API如何定义AssertionError的使用。

在这种情况下,通常会有不同的Throwable吗?通常只会向一般Exception发送一条消息吗?或者为此编写自定义Exception是常见的吗?

这是非常微不足道的,但我认为从形式和标准的角度来看,我只是对此感到好奇。

8 个答案:

答案 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();
    }

    ...
}