Какой предпочтительный Throwable для использования в конструкторе частного служебного класса?

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

  •  29-08-2019
  •  | 
  •  

Вопрос

Эффективная Java (Второе издание), Пункт 4, обсуждает использование частных конструкторов для обеспечения невозможности установки.Вот пример кода из книги:

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

Однако, AssertionError не похоже, что это то, что нужно выбрасывать.Ничто не "утверждается", именно так API определяет использование Ошибка утверждения.

Есть ли другой Throwable это типично в такой ситуации?Обычно кто-то просто бросает общий Exception с сообщением?Или это обычное дело - писать пользовательский Exception за это?

Это довольно тривиально, но больше всего, я думаю, мне просто интересно узнать об этом с точки зрения стиля и стандартов.

Это было полезно?

Решение

Есть утверждение:"Я утверждаю, что этот конструктор никогда не будет вызван".Так что, действительно, AssertionError здесь это правильно.

Другие советы

Мне нравится включать комментарий Блоха:

// Suppress default constructor for noninstantiability

Или еще лучше поместить это в сообщение Об ошибке:

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

Исключение UnsupportedOperationException звучит как наилучший вариант, хотя проверяемое исключение было бы еще лучше, поскольку оно могло бы предупредить кого-то, ошибочно создающего экземпляр класса во время компиляции.

Нет-нет-нет, при всем моем уважении к Джошу Блоху, никогда не бросайте AssertionError если только это не из утверждения. Если вам нужен AssertionError здесь, выбросьте его с assert(false).Тогда кто-то, читающий код, сможет найти его позже.

Еще лучше, определите свое собственное исключение, скажем CantInstantiateUtilityClass.тогда у вас будет код, который гласит

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

чтобы читатель " ловца " знал что случилось.

Обновить

Время от времени какой-нибудь чертов дурак забредает сюда и снова отрицает это, спустя почти четыре года после свершившегося факта.Итак, позвольте мне просто отметить, что стандартный все еще определяет 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 с атрибуция
Не связан с StackOverflow
scroll top