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

如何避免java中的许多try-catch块,java,exception-handling,Java,Exception Handling,我对java和try-catch块处理异常的想法非常陌生 这大概就是我的结局,必须有更好的方法: try { JSONObject jsonObject = new JSONObject(jsonString); int aCount = jsonObject.getInt("acount"); String devTok = jsonObject.getString("dt"); String qURL = jsonObj

我对java和try-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块或“Add-throws声明”

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


(我习惯于objective-c,其中是失败的委托方法,或者该方法返回null,并且您已经传递了指向NSError对象的指针(该对象将被“填充”),是否有地方可以了解try-catch?

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

Eclipse一直要求您这样做,因为如果检查的异常未被捕获或声明由调用方抛出,Java代码将不会编译

+在回答中添加此评论(谢谢Paul Tomblin):


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

如果您有一个代码块,其中可能引发多种类型的异常,则可以声明两个单独的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块捕获
异常
(或者
Throwable
;我记不清Java中异常的超类是什么)


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

异常处理的思想是,您可以在程序流中有意义地处理错误的地方处理错误。与在C中检查每个函数的返回值不同,在C中,大多数情况下,除了进一步传递错误外,您无法执行任何合理的操作,而是在程序中的合理点安装try/catch块

基本上,只要有一个点,你就可以对错误做出有意义的反应,然后抓住这个错误,把其他的一切都传下去。这样,只有在从错误中进行合理的恢复时才会调用错误处理

例如,最坏的情况是,如果有任何错误阻止了程序有意义地执行,那么您可能几乎什么也捕捉不到,而只是让操作系统来处理这种情况(好吧,可能是一次尝试/捕捉来生成友好的错误消息)

<强>示例(在C++中,对不起,我不能键入java盲):

在本例中,我们可能尝试处理图像,但由于某些预期的原因(内存不足或无法读取图像)而失败。在这种情况下,我们只是返回而不做任何工作,让程序继续优雅。所有其他错误都会传播到更高的点。最重要的是,我们确实不需要在实际的图像处理功能中始终进行错误检查和响应,只要那里的任何代码抛出两个好的异常中的一个就足够了,不用再担心了


寓意:如果到处都有try/catch块,那你就错了。

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

但除此之外,我能提供的唯一建议是清理代码的语法外观,告诉您可以编写:

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

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

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

try{

  xyz;

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

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

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

如果您没有从异常中恢复的方法,而您所做的只是打印堆栈跟踪,则建议向方法中添加throws声明(如eclipse所建议的),并让调用方处理异常(或将其抛出给调用方)


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

我喜欢将调用放在静态方法后面,只是为了让它更整洁。例如,下面是我的缩减集Json值调用

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;
    }
}
…然后我忽略返回值,因为我不好

某处或
public boolean isInteger(String str) {
    try {
        new Integer(str);
    }
    catch(NumberFormatException e) {
        return false;
    }
    return true;
}
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;
    }
}
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();
}
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();
} 
try {
  do smth
  try {
    do smth more
    ...
  } catch (Exception1 e1) {reaction to e1}
} catch (Exception2 e2) {reaction to e2}
try {
  do smth
  do smth more
  ...
}
catch (Exception1 e1) {reaction to e1}
catch (Exception2 e2) {reaction to e2}
try {
  do smth
  do smth more
  ...
}
catch (Exception e) {e.printStackTrace();}
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}
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();
    }
}