Как избежать многих попыток ловить блоки в Java - PullRequest
6 голосов
/ 06 июля 2011

Я очень новичок в Java и в идее пытаюсь использовать блоки catch для обработки исключений.

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

    try {
        JSONObject jsonObject = new JSONObject(jsonString);
        int aCount = jsonObject.getInt("acount");
        String devTok = jsonObject.getString("dt");
        String qURL = jsonObject.getString("qu");
        try {
            DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
            Key qKey = KeyFactory.createKey("qu", qURL);
            int dsACount = (Integer) datastore.get(qKey).getProperty(kLastKnownANumber);
            //..etc.. more try catch blocks needed
        } catch (EntityNotFoundException e) {
            e.printStackTrace();
        }
    } catch (com.google.appengine.repackaged.org.json.JSONException e) {
        e.printStackTrace();
    }

Существует больше блоков try-catch, встроенных таким же образом, так что в конце получается просто блок блоков catch. Как еще следует обрабатывать исключения, Eclipse постоянно просит my либо окружить блок try catch, либо «Добавить объявление throws».

Иногда я хочу перехватить определенные исключения, например, если он не может найти сущность, я хочу напечатать что-то вроде «Entity not found», и если строка JSON не может быть проанализирована в объекте, я хочу напечатать что-то вроде «Не могу разобрать JSON».

(Я привык к target-c, где есть методы делегата для сбоя, или метод возвращает ноль, и вы передали указатель на [указатель на] объект NSError, который будет «заполнен», там где-нибудь узнать о try-catch?)

Ответы [ 10 ]

7 голосов
/ 06 июля 2011

Если все, что вы делаете, это перехватываете и печатаете трассировку стека независимо от типа исключения, вы можете просто обернуть код в один большой блок try / catch.Чтобы сохранить много «ловушек», вы можете поймать java.lang.Throwable, который является интерфейсом, который реализуют все исключения.Если нет, вы можете иметь ловушку для каждого типа проверяемого исключения, которое выдает код, который вы вызываете, и обрабатывать их специально.

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

+ Добавление этого комментария к ответу (спасибо, Пол Томблин):

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

4 голосов
/ 06 июля 2011

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

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

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

Пример (в C ++, извините, я не могу набрать Java вслепую):

int main()
{
  try {
    while (masterloop()) { }
  catch (...) {
    LOG("Fatal program error, terminating!"); // nothing else we can do!
  }
}

/* lots of program logic */

void process_image()
{
  try {
    Image im = load_image_from_disk();
    /* ... */
  }
  catch (const OutOfMemoryExc & e) {
    LOG("Not enough memory to process the image.");
    return;
  }
  catch (const DataErrorExc & e) {
    LOG("Could not read the image data.");
    return;
  }
  catch (...) {
    throw; // pass everything else along
  }
}

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

Мораль: Если у вас есть блоки try / catch абсолютно везде, вы делаете это неправильно.

2 голосов
/ 06 июля 2011

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

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

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

private Integer getDatastoreACount() {
    try {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Key qKey = KeyFactory.createKey("qu", qURL);
        return (Integer) datastore.get(qKey).getProperty(kLastKnownANumber);
        //..etc.. more try catch blocks needed
    } catch (EntityNotFoundException e) {
        // expects an Integer return, so need to deal with this
        // but for simplicity I'm just simply recycling 'e'
        throw e;
    }
}

public void parseJSON(String jsonString) {
    try {
        JSONObject jsonObject = new JSONObject(jsonString);
        int aCount = jsonObject.getInt("acount");
        String devTok = jsonObject.getString("dt");
        String qURL = jsonObject.getString("qu");
        Integer dsACount = getDatastoreACount();
        //etc etc
    } catch (com.google.appengine.repackaged.org.json.JSONException e) {
        e.printStackTrace();
    }
}
1 голос
/ 06 июля 2011

Вы можете поймать несколько исключений в одной попытке, например,

try{

  xyz;

}catch(NullPointerException npx){
  npx.getMessage();
}catch(ArrayOutOfBoundsException ax){
  ax.getMessage();
}

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

0 голосов
/ 06 июля 2011

Если вы просто делаете что-то вроде этого:

try {
  do smth
  try {
    do smth more
    ...
  } catch (Exception1 e1) {reaction to e1}
} catch (Exception2 e2) {reaction to e2}

Вы можете сделать все за один try -блок:

try {
  do smth
  do smth more
  ...
}
catch (Exception1 e1) {reaction to e1}
catch (Exception2 e2) {reaction to e2}

Вы также можете разбить это наодин блок catch, если вы просто печатаете исключение:

try {
  do smth
  do smth more
  ...
}
catch (Exception e) {e.printStackTrace();}

Но это не так, если вы хотите сделать что-то большее, даже если выброшено e1, например:

try {
  do smth
  try {
    do smth more
    ...
  } catch (Exception1 e1) {reaction to e1}
  do smth even if e1 was thrown
} catch (Exception2 e2) {reaction to e2}

Последний пример не может быть написан короче.

0 голосов
/ 06 июля 2011

У вас есть два основных варианта выбора стиля кода (которые не требуют изменения сигнатур методов)

Метод 1: поместите все в один try catch и получите несколько блоков перехвата, например:

try {
    JSONObject jsonObject = new JSONObject(jsonString);
    int aCount = jsonObject.getInt("acount");
    String devTok = jsonObject.getString("dt");
    String qURL = jsonObject.getString("qu");
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    Key qKey = KeyFactory.createKey("qu", qURL);
    int dsACount = (Integer) datastore.get(qKey).getProperty(kLastKnownANumber);
    //..etc.. more try catch blocks needed
} catch (EntityNotFoundException e) {
    e.printStackTrace();
} catch (com.google.appengine.repackaged.org.json.JSONException e) {
    e.printStackTrace();
}

Метод 2: разбейте ваш код на разделы, каждый из которых имеет один catch, например:

String qURL = null;
try {
    JSONObject jsonObject = new JSONObject(jsonString);
    int aCount = jsonObject.getInt("acount");
    String devTok = jsonObject.getString("dt");
    String qURL = jsonObject.getString("qu");
} catch (EntityNotFoundException e) {
    e.printStackTrace();
} 

try {    
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    Key qKey = KeyFactory.createKey("qu", qURL);
    int dsACount = (Integer) datastore.get(qKey).getProperty(kLastKnownANumber);
} catch (EntityNotFoundException e) {
    e.printStackTrace();
} 

Рекомендуется метод 2, так как он делает очевидным, какие строкивыбрасывая какие исключения и обычно сегментирует код в блоки естественной обработки.

0 голосов
/ 06 июля 2011

Мне нравится упаковывать вызов за статическим методом, просто чтобы он был аккуратнее. Например, вот мой уменьшенный вызов Set Json Value.

private static boolean setJsonValue(JSONObject j,String key,Object value)
{
    try 
    {
        if(value instanceof Integer)
        {
            // numbers are special. We want them unquoted.
            int valueI = (Integer)value;
            j.put(key,valueI);
        }
        else
            j.put(key,value);
        return true;
    }
    catch (JSONException e) 
    {
        // do nothing, it turns out
        return false;
    }
}

... а потом я игнорирую возвращаемые значения, потому что я плохой.

Где-то у меня есть аналогичный метод Get, который возвращает null в случае сбоя. Вы поняли.

0 голосов
/ 06 июля 2011

Вы должны использовать блоки try / catch, если у вас есть способ восстановления из исключения, например, если вы хотите проверить, является ли строка допустимым целым числом, вы можете написать метод (это неэффективный метод, но просточтобы показать идею):

public boolean isInteger(String str) {
    try {
        new Integer(str);
    }
    catch(NumberFormatException e) {
        return false;
    }
    return true;
}

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

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

0 голосов
/ 06 июля 2011

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

Но в остальном, единственный совет, который я могу предложить, чтобы разобраться в том, как выглядит код, синтаксически, состоит в том, чтобы сказать вам, что вы можетеwrite:

try {
  ...
} catch (...) {
  ...
} catch (...) {
  ...
}

Вы также можете поймать более широкий класс исключений, такой как Exception, и просто написать один блок catch, но это плохой дизайн.В Java 7 вы сможете отлавливать несколько типов исключений в одном блоке.

0 голосов
/ 06 июля 2011

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

try {
    JSONObject jsonObject = new JSONObject(jsonString);
    int aCount = jsonObject.getInt("acount");
    String devTok = jsonObject.getString("dt");
    String qURL = jsonObject.getString("qu");

    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    Key qKey = KeyFactory.createKey("qu", qURL);
    int dsACount = (Integer) datastore.get(qKey).getProperty(kLastKnownANumber);
} catch (EntityNotFoundException e) {
    e.printStackTrace();
} catch (com.google.appengine.repackaged.org.json.JSONException e) {
    e.printStackTrace();
}
//..etc.. as many catch blocks as needed

В качестве альтернативы, если вам нет дела до точногоТип исключения, вы можете иметь только один блок catch, который ловит Exception (или, может быть, Throwable; я не могу точно вспомнить, что такое суперкласс исключений в Java).

Еще один момент, который я сделаюсделать сейчас, что вы не можете иметь самый модульный код.Помните, что код, который делает одну вещь, делает для хорошего модульного кода.Если вы обнаружите, что у вас много вложенных черных (будь то блоки try / catch, блоки if / else и т. Д.), Вы можете проверить, может ли часть кода быть извлечена в его собственный метод.Это также может сделать ваш код лучше, когда нужно обработать много исключений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...