Лучше ли использовать try/catch вместо нескольких операторов IF?

Является ли лучше, менее дорогостоящим или более читаемым использовать блок try/catch в Java вместо использования нескольких операторов If для проверки ввода пользователя, например?

Пример при синтаксическом анализе строки Date, лучше не разбираться напрямую, используя блок try/catch вместо написания нескольких операторов, ищущих незаконные символы.

В другом примере, скажем, я хочу прочитать файл или поток, вместо использования Scanner, я просто принудительно применяю метод и жду, когда произойдет исключение.

Это здоровый метод программирования? Это дешевле на виртуальной машине?

UPDATE
Вот пример того, что я имел в виду, когда с использованием исключения DateFormat, иногда это может быть реальной проблемой, чтобы поймать ошибку, и при этом может вы гарантируете, что ваш сложный (обычно нечитаемый) код подвержен ошибкам?

Ответ 1

Плохая практика использования Исключения для управления потоком.

Некоторые цитаты:

Потому что исключения предназначены для использования в исключительных случаях обстоятельства, малое, если есть, реализация JVM пытается оптимизировать их производительность. Как правило, это дорого, бросить и поймать исключение.

При наличии несвязанной ошибки, идиома может терпеть неудачу молча и маскировать ошибку, значительно усложняя отладку процесс.

Обновление: Как он сказал (и я помню, что я также нашел то же утверждение в блоге Джоша Блоха), используя исключения для управления потоком, это похоже на использование GOTO с той же целью. Вы можете прочитать интересную статью Дейкстры о том, почему GOTO плохи.

Ответ 2

В общем, исключения предназначены для... ну, исключительных событий. If предназначен для вещей, которые могут возникать во время обычного хода событий.

Как правило, если вы хотите обрабатывать случай, для которого у вас нет хорошего локального решения, используйте исключение, чтобы распространять его вверх для того, кто может справиться с ним лучше. Это значительно дороже, чем if-else, что еще одна причина не злоупотреблять им. Третий, IMHO не менее важная проблема - читаемость: гораздо труднее следовать, где поток выполнения продолжается после throw, чем читать последовательность операторов If.

Если вы хотите обрабатывать случай локально, большую часть времени лучше использовать простой If.

Ответ 3

Исключения для исключительных случаев. Это плохая идея сделать программную логику зависимой от исключений.

Ответ 4

Более дорогостоящее использование Exception вместо If, потому что у компилятора и jvm будет больше работы и сложности для оптимизации потока управления этими блоками, а в общем случае исключения для исключения.

Ответ 5

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

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

В таких случаях я бы предпочел использовать исключения, если профайлер не идентифицировал их как узкое место производительности. Но для более простых тестов (nulls, end of file) я бы сильно избегал использования исключений в качестве замены для предложений if.

Ответ 6

Я думаю, было бы дороже, если бы try catch поймал исключение плюс инструкции if, вероятно, выглядели бы чище.

Ответ 7

Когда генерируется исключение, стек сообщений копируется в новый объект Exception, чтобы включить отладку и printStackTrace(). Это дорого.

Если ваш in-thens get становится чрезмерным, рассмотрите шаблоны управления потоком, такие как шаблоны Strategy, State и Command.

Ответ 8

Попробуйте поймать дорого, только когда выбрано исключение, которое, я считаю, связано с созданием трассировки стека. Я проведу следующий тест, чтобы проверить это:

 public class TestTryCatchVsIfElseVsNoBlock
 {
    private static final int numberOfIteration = 1000000;

    public static void main(String[] args)
    {

    //measureExIfElse
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureIfElse(null);
    }
    long start = System.nanoTime();
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureIfElse(null);
    }
    final long ExIfElse = (System.nanoTime() - start);



    //measureExTryCatch
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureTryCatch(null);
    }
    start = System.nanoTime();
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureTryCatch(null);
    }
    final long ExTryCatch = (System.nanoTime() - start);


    //measureIfElse
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureIfElse("Nitin");
    }
    start = System.nanoTime();
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureIfElse("Nitin");
    }
    final long IfElse = (System.nanoTime() - start);


    //measureTryCatch
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureTryCatch("Nitin");
    }
    start = System.nanoTime();
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureTryCatch("Nitin");
    }
    final long TryCatch = (System.nanoTime() - start);


    //WithoutAnyBlock
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureWithoutAnyBlock("Nitin");
    }
    start = System.nanoTime();
    for (int i = 0; i < numberOfIteration; i++)
    {
        measureWithoutAnyBlock("Nitin");
    }
    final long WithoutAnyBlock = (System.nanoTime() - start);

    System.err.println("ExIfElse: "+ ExIfElse/(float)numberOfIteration); // 3.563198
    System.err.println("ExTryCatch: "+ ExTryCatch/(float)numberOfIteration); // 15.924681
    System.err.println("IfElse: "+ IfElse/(float)numberOfIteration); // 1.683819
    System.err.println("TryCatch: "+ TryCatch/(float)numberOfIteration); // 1.507893
    System.err.println("WithoutAnyBlock: "+ WithoutAnyBlock/(float)numberOfIteration); // 1.750418

}

private static int i = 0;
private static void measureTryCatch(String s)
{
    try
    {
        s.length();         
    }
    catch (Exception e)
    {
        ++i;
    }
}

private static void measureWithoutAnyBlock(String s)
{
    s.length();
}

private static void measureIfElse(String s)
{
    if(s!=null)
    {
        s.length();
    }
    else
    {
        ++i;
    }
}

}