Исключения или коды ошибок

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

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

Ответ 1

Я обычно предпочитаю исключения, потому что они имеют более контекстуальную информацию и могут передавать (при правильном использовании) ошибку для программиста более ясным образом.

С другой стороны, коды ошибок более легкие, чем исключения, но их сложнее поддерживать. Проверка ошибок может быть непреднамеренно опущена. Коды ошибок сложнее поддерживать, потому что вам необходимо сохранить каталог со всеми кодами ошибок, а затем включить результат, чтобы узнать, какая ошибка была выбрана. Диапазоны ошибок могут быть полезны здесь, потому что если единственное, что нас интересует, - если мы находимся в наличии ошибки или нет, ее проще проверить (например, код ошибки HRESULT, больший или равный 0, является успешным и меньше нуля - это отказ). Они могут быть непреднамеренно опущены, потому что нет программного воздействия, которое разработчик будет проверять на наличие кодов ошибок. С другой стороны, вы не можете игнорировать исключения.

Подводя итог, я предпочитаю исключения по кодам ошибок практически во всех ситуациях.

Ответ 2

В материалах высокого уровня, исключениях; в низкоуровневых материалах, коды ошибок.

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

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

Оба Raymond Chen и Joel сделали некоторые красноречивые аргументы против использования исключений для всего.

Ответ 3

Я предпочитаю исключения, потому что

  • они перехватывают поток логики
  • им выгодна иерархия классов, которая дает больше возможностей/функциональности
  • при правильном использовании может представлять собой широкий диапазон ошибок (например, InvalidMethodCallException также является LogicException, поскольку оба происходят, когда в вашем коде есть ошибка, которая должна быть обнаружена до выполнения), и
  • они могут быть использованы для улучшения ошибки (то есть определение класса FileReadException может содержать код для проверки наличия файла или блокировки и т.д.)

Ответ 4

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

Ответ 5

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

Вот несколько статей, обсуждающих, сравнивающих и противопоставляющих два метода:

Есть несколько хороших ссылок в тех, которые могут дать вам дальнейшее чтение.

Ответ 6

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

Исключения для "всего, что останавливает или препятствует методу или подпрограмме делать то, что вы просили сделать"... НЕ передавать сообщения о нарушениях или необычных обстоятельствах, состоянии системы и т.д. Использовать return значения или ref (или out) для этого.

Исключения позволяют записывать (и использовать) методы с семантикой, зависящие от функции метода, то есть метод, который возвращает объект Employee или List of Employees, может быть введен для того, чтобы сделать это, и вы можете использовать его, вызвав,

Employee EmpOfMonth = GetEmployeeOfTheMonth();

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

Employee EmpOfMonth; 
if (getEmployeeOfTheMonth(ref EmpOfMonth) == ERROR)
    // code to Handle the error here

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

Ответ 7

В прошлом я присоединился к лагерю ошибок (слишком много программировалось на C). Но теперь я видел свет.

Исключения составляют немного нагрузку на систему. Но они упрощают код, уменьшая количество ошибок (и WTF).

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

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

Ответ 8

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

Когда возникает исключение, приложение перестает следовать "нормальному" пути выполнения. Первая причина, по которой это так важно, заключается в том, что, если автор кода не будет хорошо и действительно не в своем роде, чтобы быть плохим, программа остановится и не продолжит делать непредсказуемые вещи. Если код ошибки не проверяется, и соответствующие действия не принимаются в ответ на плохой код ошибки, программа будет продолжать делать то, что делает, и кто знает, каков будет результат этого действия. Есть много ситуаций, когда программа "все" может оказаться очень дорогой. Рассмотрим программу, которая извлекает информацию о производительности для различных финансовых инструментов, которые компания продает, и доставляет эту информацию брокерам/оптовикам. Если что-то пойдет не так, и программа продолжит работу, он может отправить ошибочные данные о производительности брокерам и оптовикам. Я не знаю ни о ком другом, но я не хочу быть тем, кто сидит в офисе VPs, объясняя, почему мой код заставил компанию получить 7-значные суммы нормативных штрафов. Предоставление клиентам сообщений об ошибках обычно предпочтительнее доставки неверных данных, которые могут выглядеть "реальными", а в последней ситуации гораздо проще работать с гораздо менее агрессивным подходом, например, кодами ошибок.

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

try {
    // Normal things are happening logic
catch (// A problem) {
    // Something went wrong logic
}

... предпочтительнее:

// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}

Есть и другие мелочи об исключениях, которые тоже хороши. Имея связку условной логики, чтобы отслеживать, возвращался ли какой-либо из методов, вызываемых в функции, код ошибки, и возвращать код ошибки выше, это много плиты котла. На самом деле, это много плиты котла, которые могут пойти не так. У меня гораздо больше веры в систему исключений большинства языков, чем у гнезд крыс в выражениях if-else-if-else, которые написал "Fred-out-of-College" Фред, и у меня есть намного лучшие дела с моим временем, чем код, рассматривающий указанное гнездо крысы.

Ответ 9

Подписи методов должны сообщать вам, что делает этот метод. Что-то вроде   long errorCode = getErrorCode(); может быть хорошо, но   long errorCode = fetchRecord(); запутывает.

Ответ 10

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

Во всех остальных случаях исключения - это, вероятно, путь.

Ответ 11

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

Я использую для определения нескольких типов исключений (например: DataValidationException или ProcessInterruptExcepion) и внутри каждого исключения определяет более подробное описание каждой проблемы.

Простой пример в Java:

public class DataValidationException extends Exception {


    private DataValidation error;

    /**
     * 
     */
    DataValidationException(DataValidation dataValidation) {
        super();
        this.error = dataValidation;
    }


}

enum DataValidation{

    TOO_SMALL(1,"The input is too small"),

    TOO_LARGE(2,"The input is too large");


    private DataValidation(int code, String input) {
        this.input = input;
        this.code = code;
    }

    private String input;

    private int code;

}

Таким образом, я использую Исключения для определения ошибок категории и коды ошибок, чтобы определить более подробную информацию о проблеме.

Ответ 12

Я могу сидеть на заборе здесь, но...

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

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

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

База кода, над которой я работаю, в основном является С++, и мы используем коды ошибок почти повсеместно, но есть один модуль, который вызывает исключения для любой ошибки, включая очень необычные, и весь код, который использует этот модуль, довольно ужасен. Но это может быть только потому, что мы смешали исключения и коды ошибок. Код, который последовательно использует коды ошибок, намного проще в работе. Если наш код последовательно использовал исключения, возможно, это было бы не так плохо. Смешивание двух не работает так хорошо.

Ответ 13

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

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

Ответ 14

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

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

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

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

Но в другом направлении использование Исключений позволяет вам создавать абстракции более высокого уровня для обработки ошибок, которые могут сделать ваш код еще более выразительным и естественным. Я бы очень рекомендовал прочитать эту превосходную, но недооцененную статью эксперта С++ Андрея Александреску по поводу того, что он называет, "Принудительные действия": http://www.ddj.com/cpp/184403864. Хотя это статья на С++, принципы обычно применимы, и я успешно перевел концепцию принудительного исполнения на С#.

Ответ 15

Во-первых, я согласен с Tom answer в том, что для исключений для использования на уровне высокого уровня, а для низкоуровневых файлов используют коды ошибок, если это не Service Ориентированная архитектура (SOA).

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

public class ServiceResponse
{
    public bool IsSuccess => string.IsNullOrEmpty(this.ErrorMessage);

    public string ErrorMessage { get; set; }
}

public class ServiceResponse<TResult> : ServiceResponse
{
    public TResult Result { get; set; }
}

И используйте вот так:

public async Task<ServiceResponse<string>> GetUserName(Guid userId)
{
    var response = await this.GetUser(userId);
    if (!response.IsSuccess) return new ServiceResponse<string>
    {
        ErrorMessage = $"Failed to get user."
    };
    return new ServiceResponse<string>
    {
        Result = user.Name
    };
}

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

Ответ 16

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

Есть несколько сценариев, где исключения являются очевидным выбором:

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

  • Однако о ситуации 1 (где случается что-то неожиданное и необъяснимое, вы просто не хотите его регистрировать), исключения могут быть полезны, потому что вы можете добавить контекстуальную информацию. Например, если я получаю исключение SqlException в своих младших помощниках данных, я захочу поймать эту ошибку на низкоуровневом уровне (где я знаю команду SQL, вызвавшую ошибку), чтобы я мог захватить эту информацию и повторно бросить вызов с дополнительной информацией. Обратите внимание на волшебное слово здесь: rethrow, а не глотать. Первое правило обработки исключений: не проглатывает исключения. Кроме того, обратите внимание, что мой внутренний улов не нуждается в регистрации, потому что внешний catch будет иметь всю трассировку стека и может его зарегистрировать.

  • В некоторых ситуациях у вас есть последовательность команд, а , если какой-либо из них терпит неудачу, вы должны очистить/удалить ресурсы (*), независимо от того, является неустранимой ситуацией (которая должна быть выбрана) или восстанавливаемой ситуацией (в этом случае вы можете обрабатывать локально или в коде вызывающего абонента, но вам не нужны исключения). Очевидно, что гораздо проще поставить все эти команды в одну попытку, вместо проверки кодов ошибок после каждого метода и очистки/удаления в блоке finally. Обратите внимание, что , если вы хотите, чтобы ошибка пузырилась (что, вероятно, вы хотите), вам даже не нужно ее ловить - вы просто используете окончательно для очистки/удаления - вы должны используйте catch/retrow, если вы хотите добавить контекстуальную информацию (см. bullet 2).

    Одним примером может служить последовательность операторов SQL внутри блока транзакций. Опять же, это также "неуправляемая" ситуация, даже если вы решили поймать ее на ранней стадии (лечить ее локально, а не пузыриться вверх), она по-прежнему является <сильной > фатальной ситуацией, из которой лучшим результатом является прервать все или, по крайней мере, прервать большую часть процесса.
    (*) Это похоже на on error goto, который мы использовали в старой Visual Basic

  • В конструкторах вы можете создавать только исключения.

Сказав, что во всех других ситуациях, когда вы возвращаете некоторую информацию, по которой вызывающий абонент МОЖЕТ/СЛЕДУЕТ предпринять какое-то действие, использование кодов возврата, вероятно, является лучшей альтернативой. Это включает в себя все ожидаемые "ошибки" , потому что, вероятно, они должны обрабатываться непосредственным вызывающим абонентом, и вряд ли нужно будет пузыриться слишком много уровней в стеке.

Конечно, всегда можно рассматривать ожидаемые ошибки как исключения, а затем сразу же выходить на один уровень выше, и также можно охватить каждую строку кода в попытке поймать и предпринять действия для каждой возможной ошибки. IMO, это плохой дизайн не только потому, что он гораздо более подробный, но специально потому, что возможные исключения, которые могут быть выбраны, не очевидны без чтения исходного кода - и исключения могут быть выбраны из любого глубокого метода, создавая невидимые gotos. Они нарушают структуру кода, создавая несколько невидимых точек выхода, которые делают код трудным для чтения и проверки. Другими словами, вы никогда не должны использовать исключения как управление потоком, потому что другим будет сложно понять и поддерживать. Это может быть даже трудно понять все возможные потоки кода для тестирования.
Опять же: для правильной очистки/удаления вы можете использовать try-finally, не поймав ничего.

Наиболее популярной критикой в ​​отношении кодов возврата является то, что "кто-то может игнорировать коды ошибок, но в том же смысле кто-то может также проглатывать исключения. Легкая обработка исключений легков обоих методах. Но писать хорошую программу на основе кодов ошибок все же намного проще, чем писать программу на основе исключений. И если по какой-либо причине решается игнорировать все ошибки (старый on error resume next), вы можете легко сделать это с помощью кодов возврата, и вы не сможете сделать это без большого количества шаблонов try-catch.

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

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

Подводя итог:

  • Мне нравится использовать исключения, когда у меня возникает непредвиденная ситуация, в которой не так много, и обычно мы хотим прервать большой блок кода или даже всю операцию или программу. Это похоже на старое "on error goto".

  • Мне нравится использовать коды возврата, когда я ожидал ситуаций, в которых код вызывающего абонента может/должен предпринять некоторые действия. Это включает в себя большинство бизнес-методов, API, проверки и т.д.

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

Однако о GO он также позволяет несколько возвращаемых значений, что очень помогает в использовании кодов возврата, поскольку вы можете одновременно вернуть ошибку и что-то еще. На С#/Java мы можем достичь этого с помощью параметров, Tuples или (мои любимые) Generics, которые в сочетании с перечислениями могут предоставлять явным коды ошибок вызывающему:

public MethodResult<CreateOrderResultCodeEnum, Order> CreateOrder(CreateOrderOptions options)
{
    ....
    return MethodResult<CreateOrderResultCodeEnum>.CreateError(CreateOrderResultCodeEnum.NO_DELIVERY_AVAILABLE, "There is no delivery service in your area");

    ...
    return MethodResult<CreateOrderResultCodeEnum>.CreateSuccess(CreateOrderResultCodeEnum.SUCCESS, order);
}

var result = CreateOrder(options);
if (result.ResultCode == CreateOrderResultCodeEnum.OUT_OF_STOCK)
    // do something
else if (result.ResultCode == CreateOrderResultCodeEnum.SUCCESS)
    order = result.Entity; // etc...

Если я добавлю новый возможный возврат в свой метод, я могу даже проверить все вызывающие, если они охватывают это новое значение в инструкции switch, например. Вы действительно не можете делать это с исключениями. Когда вы используете коды возврата, вы, как правило, заранее знаете все возможные ошибки и проверяете их. С исключениями вы обычно не знаете, что может случиться. Обертка enums внутри исключений (вместо Generics) является альтернативой (до тех пор, пока она очищает тип исключений, которые будет бросать каждый метод), но IMO это все еще плохой дизайн.

Ответ 17

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

Возврат недействительных указателей, которые могут быть разыменованы (например, вызывают NullPointerException в Java), неприемлемо.

Использование нескольких разных числовых кодов ошибок (-1, -2) в качестве возвращаемых значений для одной и той же функции обычно является плохим стилем, поскольку клиенты могут выполнять проверку "== -1" вместо "< 0".

Одна вещь, о которой нужно помнить, это эволюция API с течением времени. Хороший API позволяет изменять и расширять поведение отказов несколькими способами, не разбивая клиентов. Например. если обработчик ошибки клиента проверен на наличие четырех ошибок, и вы добавите пятую ошибку в свою функцию, обработчик клиента может не протестировать это и не сломаться. Если вы создадите Исключения, это, как правило, упростит переход клиентов на более новую версию библиотеки.

Еще одна вещь, которую следует учитывать, - это работать в команде, где нужно сделать четкую линию для разработчиков alldevelopers для принятия такого решения. Например. "Исключения для материала высокого уровня, коды ошибок для низкоуровневых материалов" очень субъективны.

В любом случае, когда возможно более одного тривиального типа ошибки, исходный код никогда не должен использовать числовой литерал, чтобы возвращать код ошибки или обрабатывать его (return -7, если x == -7...), но всегда именованная константа (возвращаем NO_SUCH_FOO, если x == NO_SUCH_FOO).

Ответ 18

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

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

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

Ответ 19

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

Ответ 20

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

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

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

Ответ 21

Мое общее правило:

  • В функции может появиться только одна ошибка: используйте код ошибки (в качестве параметра функции)
  • Может появиться несколько ошибок: throw exception

Ответ 22

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