Qual è il Throwable preferito da utilizzare in un costruttore di classi di utilità privata?

StackOverflow https://stackoverflow.com/questions/398953

  •  29-08-2019
  •  | 
  •  

Domanda

Java efficace (seconda edizione), Punto 4, discute l'utilizzo di costruttori privati ​​per imporre la non istanziabilità.Ecco l'esempio di codice tratto dal libro:

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

Tuttavia, AssertionError non mi sembra la cosa giusta da buttare.Nulla viene "affermato", ecco come l'API definisce l'utilizzo di Errore di asserzione.

C'è qualcosa di diverso? Throwable è tipicamente in questa situazione?Di solito si lancia semplicemente un generale Exception con un messaggio?Oppure è comune scrivere un'usanza Exception per questo?

È piuttosto banale, ma più di ogni altra cosa credo di essere semplicemente curioso a riguardo dal punto di vista dello stile e degli standard.

È stato utile?

Soluzione

C'è un'affermazione:"Sto affermando che questo costruttore non verrà mai chiamato".Quindi, infatti, AssertionError è corretto qui.

Altri suggerimenti

Mi piace includere il commento di Bloch:

// Suppress default constructor for noninstantiability

O meglio ancora inserendolo nell'errore:

private UtilityClass()
{
    throw new AssertionError("Suppress default constructor for noninstantiability");
}

Eccezione operazione non supportata sembra la soluzione migliore, anche se un'eccezione controllata sarebbe ancora migliore, poiché potrebbe avvisare qualcuno che sta erroneamente istanziando la classe in fase di compilazione.

No no no, con tutto il rispetto per Josh Bloch, non lanciare mai un AssertionError a meno che non provenga da un'affermazione. Se vuoi un AssertionError qui, lancialo con assert(false).Quindi qualcuno che legge il codice può trovarlo più tardi.

Ancora meglio, definisci la tua eccezione, diciamo CantInstantiateUtilityClass.allora avrai il codice che dice

try {
    // some stuff
} catch (CantInstantiateUtilityClass e) {
    // react
}

in modo che il lettore del ricevitore lo sappia Che cosa accaduto.

Aggiornamento

Ogni tanto qualche dannato idiota passa di qui e lo svaluta di nuovo, quasi quattro anni dopo il fatto.Quindi, lasciatemi solo notare che lo standard Ancora definisce AssertionError come il risultato di un'affermazione fallita, non come pensa qualche principiante dovrebbe da lanciare al posto di un'eccezione informativa ben definita.Purtroppo, una buona disciplina delle eccezioni è forse l'abilità meno incoraggiata nella programmazione Java.

Quando il codice richiede l'inclusione di JUnit come dipendenza, ad esempio nell'ambito del test Maven <scope>test</scope>, quindi vai direttamente a Assertion.fail() metodo e beneficiare di un significativo miglioramento della chiarezza.

public final class UtilityClass {
    private UtilityClass() {
        fail("The UtilityClass methods should be accessed statically");
    }
}

Al di fuori dell'ambito del test, potresti utilizzare qualcosa di simile al seguente, che richiederebbe un'importazione statica da utilizzare come sopra. 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
    }
}

Quale il seguente utilizzo.

public class UtilityClassTwo {
    private UtilityClassTwo() {
        Error.fail("The UtilityClass methods should be accessed statically");
    }
}

Nella sua forma più idiomatica, si riducono tutti a questo:

public class UtilityClassThree {
    private UtilityClassThree() {
        assert false : "The UtilityClass methods should be accessed statically";
    }
}

Una delle eccezioni incorporate, non supportata operazione può essere lanciata per indicare che "l'operazione richiesta non è supportata".

 private Constructor() {
    throw new UnsupportedOperationException(
            "Do not instantiate this class, use statically.");
}

Un'asserzione non funzionante significa che hai violato una specifica contrattuale del tuo codice.Quindi è la cosa giusta qui.

Tuttavia, poiché presumo che istanziarai privatamente un'istanza, chiamerà anche il costruttore e causerà un errore, a meno che tu non abbia un altro costruttore?

Puoi creare la tua estensione di classe Throwable, per esempio.:

class NoninstantiabilityError extends Throwable

Ciò presenta i seguenti vantaggi:

  • Il nome indica il problema
  • Perché si estende direttamente Throwable è improbabile che venga catturato per sbaglio
  • Perché si estende direttamente Throwable è controllato e chiamare per sbaglio il rispettivo costruttore richiederebbe il rilevamento dell'eccezione

Esempio di utilizzo:

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

    ...
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top