簡體   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