Что быстрее попробуйте catch или if-else в java (производительность WRT)

Какой из них быстрее:

Либо этот

try {
  n.foo();
} 
catch(NullPointerException ex) {
}

, либо

if (n != null) n.foo();
35
задан Emmanuel Angelo.R 10 March 2015 в 12:56
поделиться

13 ответов

Это не вопрос о том, что быстрее, скорее вопрос о правильности.

Исключение составляют именно такие обстоятельства, исключительные .

Если n может быть null как часть нормальной бизнес-логики, тогда используйте бросок if..else , else . исключение.

53
ответ дан 27 November 2019 в 06:20
поделиться
if (n != null) n.foo();

работает быстрее.

53
ответ дан 27 November 2019 в 06:20
поделиться

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

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

  • проверять каждый кадр стека на предмет стека текущего потока и
  • создавать структуру данных для захвата деталей кадра стека.

В некоторых случаях вы можете уменьшить это, повторно используя объект исключения или переопределив метод исключения fillInStackTrace () конкретного приложения, чтобы он не выполнялся. Обратной стороной в обоих случаях является то, что правильные трассировки стека больше не будут доступны, чтобы помочь вам отладить неожиданные исключения. (И ни то, ни другое не применимо к примеру OP.)

Хотя создание исключений обходится дорого, выброс, распространение и перехват исключений также не совсем дешевы.


Есть вторая причина, по которой явное нулевое тестирование является лучшей идеей. Рассмотрим следующее:

try {
    doSomething(a.field);
} catch (NullPointerException ex) {
    System.err.println("a.field is null");
}

Что произойдет, если NPE произойдет во время вызова doSomething (...) , а не во время вычисления выражения a.field ? Конечно, мы поймаем NPE, но мы неправильно диагностируем его, а затем попытаемся продолжить ... неправильно предполагая, что a.field не задано или что-то в этом роде.

Отличить «ожидаемый» NPE от «неожиданного» NPE теоретически возможно, но на практике очень сложно. Гораздо более простой и надежный подход заключается в явном тестировании ожидаемых значений null (например, с помощью оператора if ) и обработки всех NPE как ошибок.

(Я уверен, что именно это имеет в виду @Mitch, говоря «рассматривая исключения как исключительные», но я думаю, что это помогает разъяснить ситуацию с помощью наглядного примера ...)

34
ответ дан 27 November 2019 в 06:20
поделиться

Я заметил, что я не единственный, кто читает информационный бюллетень специалиста по Java:)

Помимо того факта, что существует семантическая разница (NPE не обязательно вызвано разыменованием n , оно могло быть вызвано некоторой ошибкой в ​​ foo () ) и проблемой читабельности (try / catch более сбивает с толку для читателя, чем if ), они должны быть примерно одинаково быстрыми в случае, когда n! = null (с версией if / else, имеющей небольшое преимущество), но когда n == null if / else намного быстрее. Почему?

  1. Когда n == null , виртуальная машина должна создать новый объект исключения и заполнить его трассировку стека . Информацию о трассировке стека получить очень дорого, поэтому здесь версия try / catch намного дороже.
  2. Некоторые считают, что условные операторы работают медленнее, потому что они предотвращают конвейерную обработку команд, и, избегая явного if , они думают, что ушли дешево, когда n! = Null . Дело, однако, в том, что виртуальная машина будет выполнять неявную нулевую проверку при разыменовании ... то есть, если JIT не может определить, что n должен быть ненулевым, что он может в версии if / else. Это означает, что версии if / else и try / catch должны работать примерно одинаково. Но ...
  3. ... предложения try / catch могут повлиять на то, как JIT может вызывать встроенные методы, что означает, что он не сможет оптимизировать версию try / catch, а также версию если еще.
8
ответ дан 27 November 2019 в 06:20
поделиться

Если n.foo () вызывает внутренний вызов NPE, вы отключены от длительного сеанса отладки (или, что еще хуже, ваше приложение не работает в производственной среде ..). Просто не делай этого.

В любом случае, сколько наносекунд вы планируете сэкономить?

8
ответ дан 27 November 2019 в 06:20
поделиться

Ответ на этот вопрос не так прост, как кажется, поскольку он зависит от процента случаев, когда объект действительно является нулевым. Если это происходит очень редко (скажем, в 0,1% случаев), то это может быть даже быстрее. Чтобы проверить это, я провел несколько сравнительных тестов и получил следующие результаты (с клиентом Java 1.6):

Benchmaring with factor 1.0E-4
Average time of NullIfTest: 0.44 seconds
Average time of NullExceptionTest: 0.45 seconds
Benchmaring with factor 0.0010
Average time of NullIfTest: 0.44 seconds
Average time of NullExceptionTest: 0.46 seconds
Benchmaring with factor 0.01
Average time of NullIfTest: 0.42 seconds
Average time of NullExceptionTest: 0.52 seconds
Benchmaring with factor 0.1
Average time of NullIfTest: 0.41 seconds
Average time of NullExceptionTest: 1.30 seconds
Benchmaring with factor 0.9
Average time of NullIfTest: 0.07 seconds
Average time of NullExceptionTest: 7.48 seconds

Это кажется мне довольно убедительным. NPE просто очень медленные. (При желании я могу выложить код бенчмарка)

edit: Я только что сделал интересное открытие: при проведении бенчмарка с использованием серверной JVM результаты кардинально меняются:

Benchmaring with factor 1.0E-4
Average time of NullIfTest: 0.33 seconds
Average time of NullExceptionTest: 0.33 seconds
Benchmaring with factor 0.0010
Average time of NullIfTest: 0.32 seconds
Average time of NullExceptionTest: 0.33 seconds
Benchmaring with factor 0.01
Average time of NullIfTest: 0.31 seconds
Average time of NullExceptionTest: 0.32 seconds
Benchmaring with factor 0.1
Average time of NullIfTest: 0.28 seconds
Average time of NullExceptionTest: 0.30 seconds
Benchmaring with factor 0.9
Average time of NullIfTest: 0.05 seconds
Average time of NullExceptionTest: 0.04 seconds

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

24
ответ дан 27 November 2019 в 06:20
поделиться

Обработка исключений обычно требует больших затрат. Спецификация VM может дать вам некоторое представление о том, сколько, но в приведенном выше случае if (n! = Null) n.foo (); быстрее.

Хотя я согласен с Митчем Уитом относительно реального вопроса, так это правильность.

@Mitch Wheat - В его защиту это довольно надуманный пример. :)

2
ответ дан 27 November 2019 в 06:20
поделиться

Конструкция if работает быстрее. Условие можно легко перевести в машинный код (инструкции процессора).

Альтернатива ( try-catch ) требует создания объекта NullPointerException.

2
ответ дан 27 November 2019 в 06:20
поделиться

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

0
ответ дан 27 November 2019 в 06:20
поделиться

Во-первых, if... then ... else лучше, по многочисленным причинам, указанным другими постерами.

Однако это не обязательно быстрее! Это полностью зависит от соотношения нулевых и не нулевых объектов. Вероятно, обработка исключения, а не проверка на null занимает в сотни тысяч раз больше ресурсов, однако, если нулевой объект встречается только один раз на каждый миллион объектов, то вариант с исключением будет немного быстрее. Но не настолько быстрее, чтобы это стоило того, чтобы сделать вашу программу менее читабельной и более трудной для отладки.

0
ответ дан 27 November 2019 в 06:20
поделиться

Этот вопрос недавно обсуждался доктором Хайнцем:

http://javaspecialists.eu/webinars/recordings/ if-else-npe-teaser.mov

0
ответ дан 27 November 2019 в 06:20
поделиться

Помимо хороших ответов (используйте исключения в исключительных случаях), я вижу, что вы в основном пытаетесь избежать повсюду нулевых проверок. Java 7 будет иметь "нулевой безопасный" оператор, который будет возвращать null при вызове n? .Foo () вместо того, чтобы бросать NPE. Это заимствовано из языка Groovy. Также существует тенденция вообще избегать использования null в коде, за исключением случаев, когда это действительно необходимо (например, при работе с библиотеками). См. Этот другой ответ для более подробного обсуждения этого. Избегайте! = Null операторов

3
ответ дан 27 November 2019 в 06:20
поделиться

if-else работает быстрее, потому что блок try-catch вызывает трассировку стека исключений. Вы можете принять это за то, что блок If-Else выполняет одну инструкцию для выполнения оценки, но Try-Catch будет запускать тысячи инструкций, чтобы вызвать исключение, когда это произойдет.

0
ответ дан 27 November 2019 в 06:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: