Qual é o Throwable preferencial para usar em um construtor de classe utilitário privado?

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

  •  29-08-2019
  •  | 
  •  

Pergunta

Effective Java (Segunda Edição) , ponto 4, discute usando construtores privados para impor noninstantiability. Aqui está o exemplo de código a partir do livro:

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

No entanto, AssertionError não parece ser a coisa certa a jogar. Nada está sendo "afirmou", que é como a API define o uso de AssertionError .

Existe uma Throwable diferente que é normalmente nesta situação? Será que um geralmente apenas jogar uma Exception geral com uma mensagem? Ou é comum para escrever um Exception personalizado para isso?

É muito trivial, mas mais do que qualquer coisa que eu acho que eu sou apenas um curioso sobre isso a partir de uma perspectiva de estilo e padrões.

Foi útil?

Solução

Há uma afirmação: "Eu estou afirmando que esse construtor nunca será chamado". Então, na verdade, AssertionError é correto aqui.

Outras dicas

Gosto incluindo o comentário de Bloch:

// Suppress default constructor for noninstantiability

Ou melhor ainda colocá-lo no erro:

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

UnsupportedOperationException sons como o melhor fit, embora uma exceção verificada seria ainda melhor, uma vez que pode avisar alguém erroneamente instanciar a classe em tempo de compilação.

E sobre IllegalAcessError ? :)

Não, não, não, com todo o respeito para Josh Bloch, nunca jogue um AssertionError a menos que seja a partir de uma afirmação. Se você quer um AssertionError aqui, jogue-o com assert(false). Então, alguém lendo o código pode encontrá-lo mais tarde.

Mesmo melhor, definir a sua própria exceção, dizem CantInstantiateUtilityClass. então você vai ter um código que diz

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

para que o leitor do catcher sabe o aconteceu.

Atualizar

De vez em quando alguns Wanders maldito tolo por aqui e downvotes isso de novo, quase quatro anos após o fato. Então, deixe-me notar que o padrão ainda define AssertionError como o resultado de uma afirmação que falhou, não como o que alguns novato pensa deve para ser jogado no lugar de um bem exceção informativo definido. Infelizmente, boa disciplina exceção é, talvez, a habilidade menos encorajado em programação Java.

Quando o código exige a inclusão do JUnit como uma dependência, como dentro do maven <scope>test</scope> escopo de teste, em seguida, ir direto para o método Assertion.fail() e beneficiar de uma melhoria significativa na clareza.

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

Quando fora do âmbito de teste, você pode usar algo como o seguinte, o que exigiria uma importação estática para uso como acima. 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
    }
}

Qual o seguinte uso.

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

Na sua forma mais idiomática, todas elas se resumem a isso:

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

Um dos construído em exceções, UnsupportedOperationException pode ser jogado para indicam que 'a operação solicitada não é suportado'.

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

meio de declaração quebrado um que você já quebrou um caderno de encargos do seu código. Por isso é a coisa certa aqui.

No entanto, como eu suponho que você vai ser privada instanciar uma instância, ele irá também chamar o construtor e causar uma de erros a menos que tenha outro construtor?

Você pode criar sua própria classe Throwable estender, por exemplo:.

class NoninstantiabilityError extends Throwable

Isto tem as seguintes vantagens:

  • O nome indica o problema
  • Porque se estende directamente Throwable é improvável que ele vai ser pego por acidente
  • Porque se estende directamente Throwable é verificado e chamando o respectivo construtor por acidente exigiria captura a exceção

Exemplo de uso:

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

    ...
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top