За / против проверенных и непроверенных исключений

Пример -

public class CustomException extends RuntimeException {
    private String message;

    public CustomException(String message) {
        this.message = message;
    }
}


public class Foo {
    private int number;

    public Foo(int x) throws CustomException {
        if(x > 10 || x < 0)
            throw new CustomException("int must be [0,10]");
       number = x;
    }

    public static void main(String[] args) {
        Foo f1 = new Foo(2); //will work
        Foo f2 = new Foo(20); //throw the exception
    }
}

По сути, я создал пользовательское исключение для обработки ввода, и если этот ввод недопустим, то исключение остановит код, и объект не будет создан. В этом примере исключение является непроверенным исключением, поэтому вам не нужно помещать объект Foo, который вы хотите создать, в блок try/catch.

В конечном счете, мой вопрос - будет ли непроверенное исключение лучшим в этой ситуации, или было бы лучше иметь его в качестве проверенного исключения, и всякий раз, когда вы создаете объект Foo, он должен находиться в блоке try/catch?

2 ответа

Решение

Есть несколько способов, чтобы я решил, должно ли исключение быть отмеченным или не отмеченным.

В вашем примере вы убедитесь, что x находится между 0 и 10. Вот где решение сделать это проверено или не проверено:

Откуда вы передаете х? Это вход, который кто-то может легко набрать 11? Если это так, то это, вероятно, должно быть проверенное исключение, потому что это ошибка, которая может легко произойти и очень возможна. С другой стороны, если x просто происходит из какого-то места в коде, которое почти наверняка будет между 0 и 10, вы не должны ловить то, что, как вы знаете, никогда не произойдет. (Если вы не испортили во время написания кода)

По сути, генерируйте проверенное исключение, если это вообще возможно (чтобы вы могли справиться с этим), и не проверяйте исключения, если исключение выдается, только если вы запутались в написании кода. (Вам не нужно обрабатывать ошибку, которую вы не ожидаете -> вы должны прочитать трассировку стека этой ошибки и исправить свой код)

Пример с кодом:

public static void handleInput(int number){
    if(number > 10){
        throw CustomException("Can't be greater than 10.");
    }
}

public static void main(String[] args){
    //first example where you shouldn't check the exception
    handleInput(5); // you know that this won't throw an exception so why catch it?

    // second example where CustomException should be a checked exception
    Scanner input = new Scanner(System.in);
    handleInput(input.nextInt()); // the user could easily enter 11 or the data could be corrupt
}

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

Query query = entotyManager.createQuery(...);
Object result = query.getSingleResult();

Вызов getSingleResult() вызовет исключение NoResultException (во время выполнения, без проверки), если результата нет. Несмотря на то, что разумно, что иногда вы не получаете результата при запросе чего-либо в базе данных, команда JPA решила вернуть его как исключение, а не как нулевой результат.

Использование адреса непроверенных исключений, чтобы обеспечить способ минимизировать количество обработчиков исключений в коде (например, представьте, что каждый вызов метода-члена должен быть обернут в try-catch) и должен использоваться для задач программирования вместо того, чтобы подписывать анормальное время выполнения условия.

Таким образом, неконтролируемые исключения являются признаками проблем с кодом (невыполнение предварительных условий, логические ошибки или другие источники ситуаций, которые должны быть обнаружены во время разработки). Например, в наше время все чаще и чаще можно увидеть, как кодеры борются за то, чтобы написать огромную логику в одной строке кода:

object.method0(...).method1(...).method2(...).method3(...)...methodN(...);

Очевидная проблема с такого рода вызовами состоит в том, чтобы гарантировать, что вызовы методов всегда возвращают допустимые объекты (например, ненулевые ссылки). Если у вас нет никаких гарантий, что условие pos каждого метода выполнено, вероятность возникновения исключений NullPointerExceptions является реальной. Единственный способ справиться с такой проблемой - переписать код, чтобы проверить результат каждого предыдущего метода перед вызовом следующего или дождаться универсального дескриптора исключения (что-то вроде "Извините, что-то случилось") сводит к минимуму влияние ошибки.

В резюме:

  • будет ли неконтролируемое исключение лучше в этой ситуации, или было бы лучше иметь его в качестве проверенного исключения? В этом случае вы должны сгенерировать исключение IllegalArgumentException, так как оно достаточно хорошее и не требуется создавать новое исключение для выполнения той же задачи.

  • всякий раз, когда вы создаете объект Foo, он должен находиться внутри блока try/catch? В этом случае вы должны убедиться, что значение параметра является допустимым, прежде чем вызывать конструктор и писать логику для правильной обратной связи с вызывающей стороной (пользователем или уровнем) этого сценария.

Другие вопросы по тегам