[英]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.