Стоимость производительности кодирования “исключения управляемая разработка” в Java?

Есть ли существует какая-либо производительность, стоившая путем создания, броска и ловли исключений в Java?

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

Например, если у Вас есть метод для получения пользователя от базы данных на основе имени.

public User getUser(String name);

Однако возможно, что пользователь мог бы быть пустым, и распространено забыть проверять это перед использованием открытого метода Пользователя.

User user = getUser("adam");

int age = user.getAge();

который привел бы к NullPointerException и катастрофическому отказу. Однако, если я осуществил проверку, прежде, чем возвратить пользовательский объект, если его пустой указатель и бросает 'UserIsNullException':

public User getUser(String name) throws UserIsNullException;

Я вынуждаю конструктора думать и действовать:

try {

    User user = getUser("adam");

    int age = user.getAge();

}catch( UserIsNullException e) {

}

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

Как такой дизайн приблизился бы к производительности эффекта? Преимущества перевешивают стоимость, или она просто плохо кодирует?

Спасибо за любую справку!

ОБНОВЛЕНИЕ! Чтобы быть ясным, мое внимание не является переносом NullPointerException, как мой пример мог бы предположить. Цель состоит в том, чтобы вынудить реализатора записать попытку/выгоду, сохранив главную боль реального катастрофического отказа с тех пор a:

пользователь == пустой указатель

был забыт. Вопрос касается сравнения этих двух моделей дизайна:

int age;

try {

User user = getUser("adam");

age = user.getAge();

}catch( UserIsNullException e) {

age = 0;

}

по сравнению с:

int age;

User user = getUser("adam");

if( user != null ) {
age = user.getAge();
} else {
age = 0;
}
14
задан Nathan Hughes 24 April 2014 в 17:06
поделиться

13 ответов

Согласно вашему последнему редактированию. Я думаю ( как предложил Тони ) использование шаблона NullObject было бы более полезным здесь.

Рассмотрим третий сценарий:

class NullUser extends User {

    public static NullUser nullUser = new NullUser();

    private NullUser(){}

    public int getAge() {
        return 0;
    }
}

//Later...
int age;

User user = getUser("adam"); // return nullUser if not found.
age = user.getAge();         // no catch, no if/null check, pure polymorphism
0
ответ дан 1 December 2019 в 06:59
поделиться

Как бы такой дизайн подходил Эффект производительность? Делать преимущества извещать стоимость или просто просто Плохое кодирование?

Я сказал, что нет никакой выгоды от этого стиля программирования. Исключение следует понимать как (хорошо ...) Исключение . Это должно произойти только в нередной ситуации. Как вы определяете «нормальную ситуацию», довольно решительную мысль ...

0
ответ дан 1 December 2019 в 06:59
поделиться

Мне нравится этот стиль кодировки, так как он очень понятно о том, что происходит с точки зрения кого-то, используя ваш API. Иногда я даже имею называть методы API GetMAndatoryUser (String) и getuserornull (String) , чтобы различать методы, которые никогда не вернутся NULL и те, которые могут вернуться null .

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

boolean done = false;

// Initialise loop counter here to avoid resetting it to 0 if an Exception is thrown.
int i=0;    

// Outer loop: We only iterate here if an exception is thrown from the inner loop.
do {
  // Set up try-catch block.  Only done once unless an exception is thrown.    
  try {
    // Inner loop: Does the actual work.
    for (; i<1000000; ++i) {
      // Exception potentially thrown here.
    }

    done = true;
  } catch(Exception ex) {
    ... 
  }
} while (!done);
1
ответ дан 1 December 2019 в 06:59
поделиться

Создание исключения, создание исключения (с трассировкой стека), захват исключения, а затем сбор мусора (в конечном итоге) намного медленнее, чем простая проверка.

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

-121--2626703-

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

<appender name="BufferingForwardingAppender" type="log4net.Appender.BufferingForwardingAppender">
    <bufferSize value="512" />
    <lossy value="false" />
    <evaluator type="log4net.Core.LevelEvaluator">
        <threshold value="WARN"/>
    </evaluator>
    <appender-ref ref="RollingFileAppender" />
</appender>
-121--3250461-

Нулевые объекты могут вам помочь. На днях я читал книгу Мартина Фаулера «Рефакторинг» и она описывает использование конкретного объекта, который действует вместо возврата нулевого значения, избавляя вас от необходимости постоянно проверять NULL.

Я не буду пытаться объяснить это здесь, так как это очень хорошо описано в книге.

1
ответ дан 1 December 2019 в 06:59
поделиться

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


Даже если вы не спрашиваете, многие люди, вероятно, скажут вам подход, который вы представляете, не кажется очень привлекательным ...: - (

Код, который вы заставляете на своих абонентах, действительно уродливы, трудно написать и поддерживать.

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

  • Другой разработчик несет ответственность за проверку нумеративного пользователя, полученного от вашего API (если документация заявляет об этом ясно). Его код регулярно проверяет такие проверки внутренне, поэтому он может сделать это также после звонка к вашему API. Еще больше, что даст его кодекс некоторой однородности.

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

3
ответ дан 1 December 2019 в 06:59
поделиться

Создание исключения, создание исключения (с трассировкой стека), захват исключения, а затем сбор мусора (в конечном итоге) намного медленнее, чем простая проверка.

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

-121--2626703-

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

<appender name="BufferingForwardingAppender" type="log4net.Appender.BufferingForwardingAppender">
    <bufferSize value="512" />
    <lossy value="false" />
    <evaluator type="log4net.Core.LevelEvaluator">
        <threshold value="WARN"/>
    </evaluator>
    <appender-ref ref="RollingFileAppender" />
</appender>
-121--3250461-

Лично я думаю, что это плохая и неприятная идея.

Обычным способом побудить людей проверять значения NULL является использование аннотаций, таких как @ Nullable (и их противоположность, @ NotNull , для функций, которые гарантированно возвращают ненулевые значения). Настраивая аналогичные аннотации для параметров (так, чтобы были заданы ожидания параметров), IDE качества и средства проверки ошибок (например, FindBugs) могут затем генерировать все необходимые предупреждения, когда код не выполняет достаточной проверки.

Эти аннотации доступны в JSR-305 , и, очевидно, имеется также ссылочная реализация .


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

5
ответ дан 1 December 2019 в 06:59
поделиться

См. Этот ответ о производительности с исключениями.

в основном в вашей идее вы обертываете Runtimeexception, NullPointexception, в проверенное исключение; ИМХО, я бы сказал, что проблема может управляться на бизнес-уровне с ObjectNotFoundException: вы не нашли пользователю, тот факт, что пользователь нулевой и что это генерирует ошибки, возникает после.

1
ответ дан 1 December 2019 в 06:59
поделиться

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

int getUserAge(String userName) 
{
    int age = 0;
    UserSearchResult result = getUser(userName);
    if (result.getFoundUser())
    {
        User user = result.getUser();
        age = user.getAge();
    }
    return age;
}
0
ответ дан 1 December 2019 в 06:59
поделиться

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

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

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

7
ответ дан 1 December 2019 в 06:59
поделиться

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

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

Исключения также вызывают отклонение от «счастливого пути». Хотя это не относится к вашему примеру кода, иногда очень полезно использовать Null Object вместо того, чтобы возвращать простой null .

5
ответ дан 1 December 2019 в 06:59
поделиться

Создание исключения снижает производительность, но обычно это приемлемо, поскольку код обработки исключений выполняется только в исключительных случаях. Если вы начнете использовать исключения для управления потоком, вы измените обычный случай и сделаете их ожидаемым поведением. Я настоятельно не рекомендую это делать.

8
ответ дан 1 December 2019 в 06:59
поделиться

", что приведет к «Исключение и сбой».

«Исключение» является исключением и может быть захвачено в catch.

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

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

-121--26698-

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

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

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

-121--2626709-

Создание исключения, создание исключения (с трассировкой стека), захват исключения, а затем сбор мусора (в конечном итоге) происходит гораздо медленнее, чем простая проверка.

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

1
ответ дан 1 December 2019 в 06:59
поделиться

Документы здесь сформулированы немного странно, но точны:

Каждое значение в массиве является числом с плавающей запятой между 0,0 и 1,0 и соответствует одному элементу в массиве значений. Каждый элемент массива keyTimes определяет длительность соответствующего значения ключевого кадра как долю от общей длительности анимации. Каждое значение элемента должно быть больше или равно предыдущему значению.

В основном каждое значение указывает, в какой нормализованной точке анимации происходит данный ключевой кадр. Так что если ключевой кадр составляет 25% в анимации, значение будет 0,25. Запутанная часть документов указывает на то, что это длительность, когда на самом деле это нормализованный пункт времени.

-121--3594916-

Да, это хорошая идея.

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

Затем возникает вопрос, что с ними делать.
Некоторые ОС (см. MS и SE) предоставляют некоторые дополнительные средства отладки, поэтому полезно просто повторно бросить исключение после того, как вы его поймаете (потому что стек все равно был размотан сейчас).

int main()
{
    try
    {
        /// All real code
    }
    // I see little point in catching other exceptions at this point 
    // (apart from better logging maybe). If the exception could have been caught
    // and fixed you should have done it before here.

    catch(std::exception const& e)
    {
         // Log e.what() Slightly better error message than ...
         throw;
    }
    catch(...)   // Catch all exceptions. Force the stack to unwind correctly.
    {
        // You may want to log something it seems polite.
        throw;  // Re-throw the exception so OS gives you a debug opportunity.
    }
}
  • будет ли он хорошо играть с нитями, которые прорастают позже?

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

Если вы говорите об исключениях в дочерних потоках. Опять же, это не совсем определено (поэтому прочитайте вашу документацию), но если поток выходит через исключение (то есть функция, используемая для запуска потока выходит из-за исключения, а не возврата), то это обычно приводит к завершению приложения (то же влияние, что и выше). Поэтому всегда лучше остановить выход ВСЕХ исключений из потока.

  • не нарушит ли он сегментации обработки (захваченные в другом месте в качестве сигнала)

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

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

Не должны влиять на другие обработчики.

-121--2475397-

", что приведет к «Исключение и сбой».

«Исключение» является исключением и может быть захвачено в catch.

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

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

8
ответ дан 1 December 2019 в 06:59
поделиться
Другие вопросы по тегам:

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