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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6589489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:30:12  来源:igfitidea点击:

How to avoid many try catch blocks in java

javaexception-handling

提问by Jonathan.

I'm very new to java and the idea of try catch blocks to handle exceptions.

我对 java 和 try catch 块来处理异常的想法很陌生。

This roughly what I'm ending up with, and there simply has to be a better way:

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

    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();
    }

There are more try catch blocks embedded in the same way, so that at the end, there is just a lump of catch blocks. How else should exceptions be handled, Eclipse keeps asking my to either surround with a try catch block or "Add throws declaration".

还有更多的try catch块以同样的方式嵌入,所以最后只有一堆catch块。还应该如何处理异常,Eclipse 一直要求我用 try catch 块包围或“添加抛出声明”。

Sometimes I want to catch certain exceptions, for example if it can't find an entity, I want to print something like "Entity not found", and if the JSON string can't be parsed into an object, I want to print something like "Can't parse JSON".

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

(I'm used to objective-c where the are delegate methods for failure, or the method returns null and you have passed a pointer to [a pointer to] an NSError object, which will have been "filled", Is there somewhere to learn about try-catch?)

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

回答by lobster1234

If all you're doing is catching them and printing the stack trace regardless of the exception type, you can just wrap the code in one large try/catch block. To save many "catches", you can catch java.lang.Throwablewhich is the interface that all exceptions implement. If not, you can have a catch for every type of checked exception the code you're calling throws, and handle them specifically.

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

Eclipse keeps asking you to do so because Java code will not compile if the checked exceptions are not caught, or declared to be thrown by the caller.

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

+Adding this comment to the answer (Thanks, Paul Tomblin):

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

In production quality apps you'd be logging the trace, adding some logic where you're handling the exception in a right way, taking an alternate flow, and/or re-wrapping it in another exception and throwing it, etc. It all depends on the particular problem you're trying to solve.

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

回答by Kerrek SB

The idea of exception handling is that you can handle errors at points in your program flow where you can deal with them meaningfully. Rather than checking every function's return value like in C, where most of the time you can't do anything sensible other than passing the error further up, you install a try/catch block at sensible pointsin your program:

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

Basically, whenever there is a point where you canreact meaningfully to an error, then catch that error, and pass everything else on. That way, error handling is only invoked when there is a plausible recovery from the error.

基本上,只要有一点可以对错误做出有意义的反应,就可以捕获该错误,然后将其他所有内容都传递下去。这样,错误处理仅在从错误中得到合理恢复时才被调用。

For example, worst case if anyerror stops your program from executing meaningfully, then you might almost not catch anything at all and just let the OS handle the situation (well, perhaps one single try/catch to produce a friendly error message).

例如,在最坏的情况下,如果任何错误阻止您的程序有意义地执行,那么您可能几乎不会捕获任何东西,而只是让操作系统处理这种情况(好吧,也许一次 try/catch 以产生友好的错误消息)。

Example(in C++, sorry, I'm can't type Java blind):

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

In this example, we may try to process an image and fail for some anticipable reasons (out of memory, or failure to read the image). In that case we just return without doing work and let the program continue gracefully. All other errors are propagated up to a higher point. Most importantly, we do notneed to litter the actual image processing function with error checks and responses all the time, it suffices for any code there to throw one of our two good exceptions and not worry any further.

在此示例中,我们可能会尝试处理图像,但由于某些可预见的原因(内存不足或无法读取图像)而失败。在这种情况下,我们只是不做任何工作就返回,让程序优雅地继续。所有其他错误都会传播到更高的点。最重要的是,我们并不需要用垃圾错误检查和响应所有的时间实际的图像处理功能,它满足任何代码在那里把我们两个很好的一个例外,而不必担心任何进一步。

Moral:If you have try/catch blocks absolutely everywhere, you're doing it wrong.

道德:如果你绝对到处都有 try/catch 块,那你就错了。

回答by Charles Goodwin

I know there's a lot of answers here, and they do a good job of covering how to structure the try/catch blocks. However, I'm thinking one of the things bothering you is the significant... indentation and code growth (... because I know it's not the indentation or amount of code, but the implied complexity by wrapping it and shifting it over and growing longer and longer between the opening try and enclosing catch, and I can't put a word to that apprehension).

我知道这里有很多答案,他们在介绍如何构建 try/catch 块方面做得很好。但是,我认为困扰您的一件事是显着的...缩进和代码增长(...因为我知道这不是缩进或代码量,而是通过包装它并将其转移和在开始尝试和封闭捕获之间越来越长,我无法表达这种担忧)。

The way to get around this is to refactor into functions the distinct bits in the code. I know it's a simplistic answer, but it's a good way to isolate individual tasks and keep the error handling fairly local to the code that requires it without padding things out vertically and horizontally with nested try/catch blocks.

解决这个问题的方法是将代码中的不同位重构为函数。我知道这是一个简单的答案,但它是隔离单个任务并使错误处理相对于需要它的代码相当本地化的好方法,而无需使用嵌套的 try/catch 块在垂直和水平方向上填充内容。

You can make these methods private as they are intended for internal use only, presumably.

您可以将这些方法设为私有,因为它们可能仅供内部使用。

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();
    }
}

回答by binfalse

If you're just doing something like this:

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

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

You can do everything in one try-block:

您可以在一个try块中完成所有操作:

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

You can also break this down to one catch block if you're just printing the exception:

如果您只是打印异常,您也可以将其分解为一个 catch 块:

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

But this doesn't if you want to do somthing more, even if e1is thrown, like:

但是如果你想做更多的事情,即使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}

The last example can't be written shorter.

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

回答by jpredham

You can catch multiple exceptions in the same try e.g.

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

try{

  xyz;

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

Also, by declaring the Exception as throwsin your method signatures you can pass the Exception up the stack.

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

回答by MByD

You should use try/catch blocks if you have a way to recover from the exception, for example if you want to check if a string is a valid integer, you can write a method (this is a lame method, but just to show the idea):

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

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

If you don't have a way to recover from the exception and all you do is to print the stack trace, it is suggested to add throws declaration (as eclipse suggest) to the method, and let the caller handle the exception (or throw it to its caller).

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

If you want to handle some exceptions and throw some other, you can do it as well.

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

回答by david van brink

I like to box up the call behind a static method, just to keep it tidier. For example, here's my reduced Set Json Value call.

我喜欢在静态方法后面封装调用,只是为了让它更整洁。例如,这是我简化的 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;
    }
}

...and then I ignore the return values, because I am bad.

...然后我忽略了返回值,因为我很糟糕。

Somewhere or other I have a similar Get method, that returns null if it fails. You get the idea.

某处或其他地方我有一个类似的 Get 方法,如果失败则返回 null。你明白了。

回答by Bohemian

You have two basic code-style choices here (that don't involve changing method signatures)

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

Method1: Put everything in the one try catchand have multiple catch blocks, like this:

方法一:把所有东西放在一个里面,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();
}

Method 2: Break up your code into sections that each have one catch, like this:

方法 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();
} 

Method 2 is the recommended one, as it makes it obvious which lines are throwing which exceptions and generally segments the code into natural processing blocks.

方法 2 是推荐的方法,因为它使哪些行抛出哪些异常一目了然,并且通常将代码分段为自然处理块。

回答by Sean Owen

First, from a design perspective, catching and printing exceptions is not a good thing. Something went wrong, and your code just keeps going in the same way as if it went right. That is not usually correct. So: perhaps your method needs to throw these exceptions instead of catching them. Perhaps only the caller is in a position to decide what happens if something fails like this.

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

But otherwise, the only advice I can offer to clean up how the code looks, syntactically, is to tell you that you can write:

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

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

You can also catch for a broader exception class like Exceptionand just write one catch block but this is bad design. In Java 7, you will be able to catch for several exception types in one block.

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

回答by Ken Wayne VanderLinde

If you have a block of code in which more than one type of exception may be thrown, you can declare two separate catch blocks:

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

Alternatively, if you don't care about the exact type of the exception, you can have onyl one catch block which catches Exception(or maybe Throwable; I can't remember exactly what the superclass of exceptions is in Java).

或者,如果您不关心异常的确切类型,您可以只有一个捕获块Exception(或者可能Throwable;我记不清 Java 中异常的超类是什么)。

Another point I will make now is that you might not have the most modular code. Remember, code that does one thing well makes for good, modular code. If you find that you have many nested black (whether try/catch blocks, if/else blocks, etc.) you may want to check if some of the code can be extracted into its own method. This may also make your code look better when many exceptions must be handled.

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