0

Java: накладные расходы if vs. try/catch

15

Есть ли какая-либо экономия производительности в Java при использовании блока try/catch по сравнению с конструкцией if (при условии, что заключенный код в остальном не вызывает ошибок)?

Например, рассмотрим две простые реализации метода "безопасной обрезки" строк:

public String tryTrim(String raw) {
    try {
        return raw.trim();
    } catch (Exception e) {
    }
    return null;
}

public String ifTrim(String raw) {
    if (raw == null) {
        return null;
    }
    return raw.trim();
}

Если входной параметр raw редко бывает null, существует ли разница в производительности между этими двумя методами?

Кроме того, является ли хорошей практикой использовать подход с tryTrim() для упрощения структуры кода, особенно когда множество блоков if, проверяющих редкие условия ошибок, могут быть заменены одним блоком try/catch?

Например, часто можно столкнуться с методом, который имеет N параметров, из которых M <= N используется в начале, быстро и детерминированно завершая выполнение, если любой из таких параметров "неверный" (например, null или пустая строка), не влияя на остальную часть кода.

В таких случаях, вместо того чтобы писать k * M блоков if (где k — среднее число проверок на параметр, например, k = 2 для проверки на null или пустые строки), блок try/catch значительно сократит код, и можно использовать 1-2 строчные комментарии для явного указания на "нетрадиционную" логику.

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

3 ответ(ов)

0

Я понимаю, что вы спрашиваете о накладных расходах на производительность, но действительно не стоит использовать try/catch и if взаимозаменяемо.

try/catch предназначен для обработки ситуаций, которые выходят за пределы вашего контроля и не являются частью обычного потока программы. Например, если вы пытаетесь записать данные в файл, а файловая система заполнена — эта ситуация обычно должна обрабатываться с помощью try/catch.

В то время как условные операторы if должны использоваться для нормальных проверок потока выполнения и обычной обработки ошибок. Например, если пользователь не заполнил необходимое поле ввода — для этого следует использовать if, а не try/catch.

На мой взгляд, ваш пример кода явно указывает на то, что правильный подход в этом случае — это оператор if, а не try/catch.

Что касается вашего вопроса, я бы предположил, что в общем случае try/catch имеет больше накладных расходов по сравнению с if. Чтобы узнать это точно, используйте профайлер Java и проверьте конкретный код, который вас интересует. Возможно, что ответ будет варьироваться в зависимости от ситуации.

0

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

Что касается этого вопроса, не перехватывайте Exception здесь, особенно не игнорируйте его. В вашем случае вы ожидаете NullPointerException. Если вы все же хотите что-то перехватить, это именно то, что стоит перехватить (но вернитесь к первому пункту, не делайте этого). Когда вы перехватываете (и игнорируете!) Exception, вы говорите: "неважно, что пойдет не так, я с этим справлюсь. Мне не важно, что это". Ваша программа может оказаться в необратимом состоянии! Перехватывайте только то, с чем вы готовы иметь дело, пусть все остальное передается слоям, которые могут с этим справиться, даже если это самый верхний уровень, и вся его задача – просто записать исключение в лог и затем завершить работу.

0

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь