如何避免java中的许多try catch块

时间:2011-07-05 22:17:58

标签: java exception-handling

我是java的新手,并尝试使用catch 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一直要求我使用try catch块或“添加throws声明”。

有时我想捕获某些异常,例如,如果它找不到实体,我想打印类似“未找到实体”的内容,如果JSON字符串无法解析为对象,我想要打印类似“无法解析JSON”的内容。

(我习惯于使用objective-c作为失败的委托方法,或者方法返回null,并且你已经传递了一个指针指向一个NSError对象的指针,该对象将被“填充”,是有什么地方可以学习try-catch吗?)

11 个答案:

答案 0 :(得分:7)

如果你正在做的就是捕捉它们并打印堆栈跟踪而不管异常类型如何,你可以将代码包装在一个大的try / catch块中。要保存许多“捕获”,您可以捕获java.lang.Throwable,这是所有异常实现的接口。如果没有,你可以捕获你正在调用的代码抛出的每种类型的已检查异常,并专门处理它们。

Eclipse一直要求您这样做,因为如果未捕获已检查的异常,或者声明被调用者抛出,则Java代码将无法编译。

+将此评论添加到答案中(谢谢,Paul Tomblin):

在生产质量的应用程序中,您将记录跟踪,添加一些逻辑,您正在以正确的方式处理异常,采用备用流程,和/或将其重新包装在另一个异常中并抛出它等等这一切都取决于你想要解决的具体问题。

答案 1 :(得分:4)

异常处理的想法是,您可以在程序流中的各个点处理错误,您可以在其中有意义地处理它们。而不是像在C中那样检查每个函数的返回值,在大多数情况下,除了将错误进一步传递之外,你不能做任何合理的事情,你在你的安全点安装一个try / catch块程序:

基本上,每当能够对错误做出有意义的反应时,就会捕获该错误并传递其他所有内容。这样,只有在从错误中恢复合理时才会调用错误处理。

例如,最糟糕的情况是,如果任何错误阻止程序执行有意义的操作,那么您可能几乎找不到任何东西,只是让操作系统处理这种情况(好吧,也许只有一次尝试/ catch以产生友好的错误消息)。

示例(在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
  }
}

在此示例中,我们可能会尝试处理图像并因某些可预期的原因(内存不足或无法读取图像)而失败。在这种情况下,我们只是返回而不做工作,让程序继续优雅。所有其他错误都会传播到更高的点。最重要的是,我们需要一直使用错误检查和响应来丢弃实际的图像处理功能,只要在那里任何代码都可以抛出我们的两个好例外之一而不用担心。

道德:如果您在任何地方都尝试过/阻止阻止,那么你做错了。

答案 2 :(得分:2)

我知道这里有很多答案,并且他们很好地介绍了如何构建try / 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();
    }
}

答案 3 :(得分:1)

您可以在同一尝试中捕获多个例外,例如

try{

  xyz;

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

此外,通过在方法签名中将异常声明为throws,您可以将异常传递到堆栈中。

答案 4 :(得分:0)

如果你有一个代码块,其中可能抛出多种类型的异常,你可以声明两个单独的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

或者,如果您不关心异常的确切类型,您可以使用onyl one catch块来捕获Exception(或者Throwable;我不记得究竟是什么超类异常在Java中。)

我现在要说的另一点是你可能没有最模块化的代码。请记住,做好一件事的代码可以实现良好的模块化代码。如果您发现有许多嵌套黑色(无论是try / catch块,if / else块等),您可能需要检查是否可以将某些代码提取到自己的方法中。当必须处理许多异常时,这也可能使您的代码看起来更好。

答案 5 :(得分:0)

首先,从设计角度来看,捕获和打印异常并不是一件好事。出了点问题,你的代码就像它正确的方式一样继续前进。这通常不正确。所以:也许你的方法需要抛出这些异常而不是捕获它们。也许只有调用者能够决定如果出现这样的事情会发生什么。

但是,除此之外,我能提供的唯一建议是清除代码的外观,从语法上来说,就是告诉你可以写:

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

您还可以捕获更广泛的异常类,如Exception,只需编写一个catch块,但这是糟糕的设计。在Java 7中,您将能够在一个块中捕获多个异常类型。

答案 6 :(得分:0)

如果你有办法从异常中恢复,你应该使用try / catch块,例如,如果你想检查一个字符串是否是一个有效的整数,你可以写一个方法(这是一个蹩脚的方法,但只是表明这个想法):

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

如果你没有办法从异常中恢复,你所做的只是打印堆栈跟踪,建议在方法中添加throws声明(如eclipse建议),并让调用者处理异常(或将其扔给呼叫者)。

如果你想处理一些异常并抛出其他异常,你也可以这样做。

答案 7 :(得分:0)

我喜欢在静态方法后面打电话,只是为了让它更整洁。例如,这是我减少的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。你明白了。

答案 8 :(得分:0)

这里有两种基本的代码风格选择(不涉及更改方法签名)

方法1:将所有内容放在try catch中,并有多个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是推荐的方法,因为它可以明显地将哪些行抛出哪些异常并且通常将代码分段为自然处理块。

答案 9 :(得分:0)

如果您正在做这样的事情:

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}

最后一个例子不能写得更短。

答案 10 :(得分:0)

创建另一个异常,并将其置于另一个异常的下方或上方。取决于您的应用程序上下文。