繁体   English   中英

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

[英]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听起来是最合适的,尽管检查异常会更好,因为它可能会警告某人在编译时错误地实例化类。

不不不,出于对 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM