Должен ли я генерировать исключения в блоке if-else?

Вот код:

public Response getABC(Request request) throws Exception {
    Response res = new Response();
    try {
        if (request.someProperty == 1) {
            // business logic
        } else {
           throw new Exception("xxxx");
        }
    } catch (Exception e) {
        res.setMessage(e.getMessage); // I think this is weird
    }
    return res;
}

Эта программа работает нормально. Я думаю, что это должно быть переработано, но как?

Ответ 1

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

Ваш код будет иметь больше смысла таким образом:

public Response getABC(Request request) {
    Response res = new Response();
    if (request.someProperty == 1) {
        // business logic
    } else {
        res.setMessage("xxxx");
    }
    return res;
}

Блок try-catch вам нужен только в том случае, если ваша бизнес-логика (выполняется при выполнении условия true) может генерировать исключения.

Если вы не поймаете исключение (что означает, что вызывающий объект должен будет его обработать), вы можете обойтись без предложения else:

public Response getABC(Request request) throws Exception {
    if (request.someProperty != 1) {
        throw new Exception("xxxx");
    }

    Response res = new Response();
    // business logic
    return res;
}

Ответ 2

если вы вызываете исключение из метода, тогда зачем его ловить? он либо возвращает ответ с сообщением "xxxx", либо выдает исключение для вызывающей стороны этого метода для его обработки.

public Response getABC(Request requst) {
    Response res = new Response();
        if(request.someProperty == 1){
            //business logic
        else{
           res.setMessage("xxxx");
        }
    }
    return res;
}

ИЛИ ЖЕ

public Response getABC(Request requst) throw Excetpions {
    Response res = new Response();
        if(request.someProperty == 1){
            //business logic
        else{
           throw new Exception("xxxx");
        }
    return res;
}


public void someMethod(Request request) {
    try {
        Response r = getABC(request);
    } catch (Exception e) {
        //LOG exception or return response with error message
        Response response = new Response();
        response.setMessage("xxxx");
        retunr response;
    }

}

Ответ 3

это не кажется правильным, когда намеренно выбрасываете исключение, а затем непосредственно перехватываете его, это может быть изменено следующим образом,
можно изменить throw new Exception("xxxx"); с res.setMessage("xxxx"); ,
и затем может сохранить часть перехвата исключения, чтобы перехватить исключение, которое может произойти внутри бизнес-логики.

public Response getABC(Request requst) {
  Response res = new Response();
  try{
      if(request.someProperty == 1){
          //business logic
      else{
         res.setMessage("xxxx");
      }
  }catch(Exception e){
      res.setMessage(e.getMessage);
  }
  return res;
}

Ответ 4

Прежде всего, действуйте осторожнее при рефакторинге метода работы, особенно если вы выполняете рефакторинг вручную. Тем не менее, введение переменной для хранения message может быть одним из способов изменения дизайна:

public Response getABC(Request requst) throw Excetpions {
    String message = "";
    try{
        if(request.someProperty == 1){
            //business logic
        else{
           message = "xxxx";
        }
    }catch(Exception e){
        message = e.getMessage();
    }
    Response res = new Response();
    res.setMessage(message);
    return res;
}

Предполагается, что business logic сама возвращается, когда это удается.

Ответ 5

Я думаю, что вы можете упустить смысл этой попытки/поймать. Код использует систему исключений, чтобы сообщать вызывающему абоненту любое сообщение об исключении. Это может быть глубоко внутри вложенного стека вызовов, а не только одного "броска", на который вы смотрите.

Другими словами, объявление "throws" в вашем примере кода использует этот механизм для доставки сообщения клиенту, но почти наверняка не является основным предполагаемым пользователем try/catch. (Также это неаккуратный, довольно дешевый способ доставить это сообщение - это может привести к путанице)

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

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

Ответ 6

Почему вы использовали оператор try/catch, когда вы уже выбросили Checked Exception?

Проверенное исключение обычно используется в некоторых языках, таких как C++ или Java, но не в новом языке, таком как Kotlin. Я лично ограничиваю его использование.

Например, у меня есть такой класс:

class ApiService{
    Response getSomething() throw Exception(); 
} 

который чувствует себя чистым и читаемым, но подрывает полезность механизма обработки исключений. Практически, getSomething() не getSomething() проверенное исключение, но все еще должен вести себя как он? Это работает, когда есть кто - то выше по течению от ApiService, кто знает, как бороться с непредсказуемыми или непредотвратимыми ошибками, как это. И если вы действительно можете знать, как с этим справиться, тогда используйте что-то вроде приведенного ниже примера, в противном случае было бы достаточно Unchecked Exception.

public Response getSomething(Request req) throws Exception{
    if (req.someProperty == 1) {
        Response res = new Response();
        // logic 
    } else {
        thows Exception("Some messages go here")
    }
}

Я призываю сделать так:

public Response getSomething(Request req){
if (req.someProperty == 1) {
        Response res = new Response();
        // logic 
        return res;
    } else {
        return ErrorResponse("error message"); // or throw RuntimeException here if you want to
    }
}

Для большего понимания, Kotlin котором я упоминал ранее, не поддерживает исключение Checked по многим причинам.

Ниже приведен пример интерфейса JDK реализованного классом StringBuilder:

Appendable append(CharSequence csq) throws IOException;

О чем говорит эта подпись? Он говорит, что каждый раз, когда я добавляю строку к чему-либо (StringBuilder, какой-то журнал, консоль и т.д.), Я должен ловить эти IOExceptions. Зачем? Потому что он может выполнять IO (Writer также реализует Appendable)... Так что это приводит к такому виду кода повсюду:

try {
    log.append(message)
}
catch (IOException e) {
    // Must be safe
}

И это нехорошо, см. Effective Java, 3-е издание, пункт 77: не игнорируйте исключения.

Посмотрите на эти ссылки:

Ответ 7

Механизм исключения имеет три цели:

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

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

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

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

Ответ 8

То же самое, если вы хотите получить конкретное сообщение об исключении, возвращаемое JVM при сбое, тогда вы можете использовать try-catch с методами getMessage() или printStackTrace() в блоке catch. Так что здесь вы можете изменить свой код следующим образом:

public Response getABC(Request request) throws Exception {
    Response res = new Response();
    try {
        if (request.someProperty == 1) {
            // business logic
        } 
    } catch (Exception e) {
        res.setMessage(e.getMessage); 
    }
    return res;
}