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

我是java的新手,并尝试使用catch catch来处理exception。

这大致是我最终的结果,而且必须有一个更好的方法:

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块。 如何处理exception,Eclipse一直要求我使用try catch块或“添加throws声明”。

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

(我习惯于使用objective-c作为失败的委托方法,或者方法返回null并且你已经传递了一个指向[指向] NSError对象的指针,该对象将被“填充”,是否存在于某处了解try-catch?)

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

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

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

在生产质量的应用程序中,您将记录跟踪,添加一些逻辑,您正在以正确的方式处理exception,采取备用流程,和/或将其重新包装在另一个exception中并抛出它等等。取决于您尝试解决的特定问题。

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

基本上,只要有一个点你可以对错误做出有意义的反应,那么就抓住那个错误,并传递其他所有内容。 这样,只有在从错误中恢复合理时才会调用error handling。

例如,最糟糕的情况是,如果任何错误使程序无法执行有意义的执行,那么您可能几乎不会捕获任何内容,只是让操作系统处理这种情况(好吧,也许只有一个try / 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 } } 

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

道德:如果你在任何地方都尝试/捕获块,那你做错了。

我知道这里有很多答案,他们很好地介绍了如何构建try / catch块。 但是,我认为困扰你的事情之一就是重要的…缩进和代码增长(…因为我知道这不是缩进或代码量,而是隐藏的复杂性,包装它并将其转移到在开放尝试和封闭捕获之间越来越长,我无法对这种担忧说一句话。

解决这个问题的方法是将函数重构为代码中的不同位。 我知道这是一个简单的答案,但它是一个很好的方法来隔离单个任务,并使error handling保持相当本地的代码,而不需要使用嵌套的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(); } } 

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

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

此外,通过将Exception声明为方法签名中的throws ,您可以将Exception传递给堆栈。

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

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

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

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

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

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

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

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

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

如果你没有办法从exception中恢复,你所做的只是打印堆栈跟踪,建议在方法中添加throws声明(如eclipse建议),并让调用者处理exception(或抛出)它的来电者)。

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

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

这里有两个基本的代码样式选择(不涉及更改方法签名)

方法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是推荐的方法,因为它显然哪些行抛出哪些exception并且通常将代码分段为自然处理块。

如果你只是做这样的事情:

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

你可以在一个try -block中做所有事情:

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

如果您只是打印exception,也可以将其分解为一个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} 

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