简体   繁体   English

Java-如何正确处理try catch块

[英]Java - How to properly handle a try catch block

I was wondering what is the proper convention for handling a try/catch block. 我想知道什么是处理try / catch块的正确约定。 It is pretty obvious what should be within the try block but what about the catch block? 很明显, try块中应该包含什么,但是catch块又如何呢?

Can I write a message to the user like the following: 是否可以向用户发送如下消息:

       do {
            try {
                System.out.println("Pi to the number of decimal places:");
                Scanner in = new Scanner(System.in);
                userNth = in.nextInt();
            } catch (Exception e) {
                System.out.println("Error: Enter a number between 1 and 100");
            }
        } while(userNth < 1 || userNth > piDecimals);

Or is this bad practice? 还是这是不好的做法?

Exception-handling is not the place to make rash assumptions; 异常处理不是做出粗鲁假设的地方; usually by the time this part of your code has been executed it's because something unanticipated has happened, this is when you want to be most careful to be accurate about detecting and recording what happened so that you can tell what needs fixing. 通常,在执行这部分代码时,是因为发生了意外的情况,这时您要非常小心地准确地检测和记录发生的事情,以便知道需要解决的问题。

The choice of Exception as the type of exception that gets caught is too broad. 将Exception作为捕获的异常类型的选择范围太广。 The method you're calling throws 3 different exceptions for distinctly different reasons; 您正在调用的方法由于明显不同的原因而引发3个不同的异常。 only one of which is something that should be caught here. 只有其中一项是应该在这里捕获的。 Also unchecked exceptions like NullPointerException will get caught by this. 同样,诸如NullPointerException之类的未经检查的异常也会被此捕获。 If you were to add some code to this catch block that inadvertently introduced a NPE it would be hard to figure out what went wrong. 如果要在此catch块中添加一些代码,而无意中引入了NPE,则很难弄清楚出了什么问题。 Your overbroad catch can result in bugs not being found or errors not getting handled properly. 过度捕获可能导致找不到错误或未正确处理错误。

(Btw Makoto makes a good point that nextInt isn't what you should be calling here anyway.) (顺便说一句,Bakto Makoto很好地指出,无论如何,nextInt都不是您应该在这里所说的。)

Not logging the exception can be acceptable in narrow cases where you're certain of what the exception means (for instance, if you caught InputMismatchException, or NumberFormatException in Makoto's example code). 在确定异常含义的狭义情况下(例如,如果在Makoto的示例代码中捕获了InputMismatchException或NumberFormatException),不记录异常是可以接受的。 But in combination with catching Exception it has the capacity to hide errors and cause confusion. 但是结合捕获Exception,它可以隐藏错误并引起混乱。

You likely chose to catch Exception because handling a bunch of different checked exceptions, most of which seemed unlikely to ever happen anyway, seemed like an intolerable nuisance. 您可能选择捕获Exception是因为处理大量不同的已检查异常,这些异常似乎无论如何都不会发生,似乎令人无法忍受。 Providing a consistent way of handling and logging exceptions will help, by providing a reasonable default case for exceptions you don't know what to do with. 通过为您不知道如何处理的异常提供合理的默认情况,提供一致的处理和记录异常的方式将有所帮助。 That way if you see an exception you just can't handle, you always have the option of letting it be thrown (possibly catching it and wrapping it in an unchecked exception), knowing that if thrown it will get logged and end your program. 这样,如果您看到无法处理的异常,则始终可以选择引发该异常(可能是捕获该异常并将其包装在未经检查的异常中),知道如果引发该异常将被记录并结束程序。

For a very small command-line program sometimes it's entirely ok to let exceptions that you can't handle be thrown from main (by adding throws Exception to the main method). 对于很小的命令行程序,有时完全可以将无法处理的异常从main中抛出(通过将throws Exception添加到main方法中)。 This is ok for toy examples, small school projects, etc.; 可以用于玩具示例,小型学校项目等; I'd only use it in production code if there was a plan for logging the output (like a batch file that redirects stderr to a file): 如果有计划记录输出(例如将stderr重定向到文件的批处理文件),则仅在生产代码中使用它:

public static void main(String... args) throws Exception {
    ... application code
}

In most cases all the main method code should be placed in a try block where any Throwable is caught and logged: 在大多数情况下,所有主要方法代码都应放置在try块中,在其中捕获并记录任何Throwable:

public static void main(String... args) {
    try {
        ... application code here
    }
    catch (Throwable t) {
        logger.log(t);
    }
}

Either alternative makes it less tempting for you to inappropriately swallow inconvenient checked exceptions. 两种选择都可以使您减少不适当地吞咽不便的检查异常的诱因。

Simple Answer: what you wrote is fine 简单的答案:你写的很好

Longer Answer: try-catch blocks are for executing code that may throw an exception, and then handling said exception if it occurs. 更长的答案:try-catch块用于执行可能引发异常的代码,然后在发生异常时对其进行处理。 In general, the catch block should have code that handles the exception however you need to handle it. 通常,catch块应具有处理异常的代码,但是您需要对其进行处理。 If the statement you currently have is how you want to respond to an exception, then it's fine by convention. 如果您当前拥有的语句是您希望如何响应异常,那么按惯例就可以了。 Some common things to do in a catch block are: 在catch块中要做的一些常见事情是:

  • Throw another exception that encapsulates the thrown exception. 引发另一个封装了引发的异常的异常。 (I often do this when parsing so that there can be a single ParseException) (我经常在解析时执行此操作,以便可以有一个ParseException)
  • Throw a runtime exception encapsulating the thrown exception and let java's default uncaught exception handler deal with it. 抛出封装了抛出异常的运行时异常,并让Java的默认未捕获异常处理程序处理该异常。 (I do this a lot when I'm writing quick temporary programs and I don't want to deal with checked exceptions) (在编写快速的临时程序并且不想处理检查的异常时,我经常这样做。)
  • Pass it to some generic handler in your program, such as a GUI to display the error, etc. 将其传递给程序中的某些通用处理程序,例如用于显示错误的GUI等。
  • call printStacktrace on it 调用printStacktrace

But anything that fits your exception-handling needs is fine 但是任何符合您的异常处理需求的方法都可以

In all actuality, this code is not going to function the way you intend it to. 实际上,此代码不会按您预期的方式起作用。 There are two key reasons for this: 造成这种情况的主要原因有两个:

  • nextInt() blocks until it receives an integer; nextInt()阻塞直到接收到整数; that is, it's not going to care about what input you give it until it reads an integer, and 也就是说,在读取整数之前,它不会关心您提供的输入,并且
  • Even if this were to be okay, depending on how you initialize userNth and piDecimals , one or both of those variables may not be defined, thus preventing compilation. 即使可以,根据您初始化userNthpiDecimals ,也可能未定义其中一个或两个变量,从而阻止了编译。

Also, don't catch Exception . 另外, 不要捕获Exception Be as specific as you can when catching exceptions, since Exception also includes some nifty and dangerous RuntimeException s like NullPointerException . 捕获异常时,请尽可能具体,因为Exception还包括一些漂亮而危险的RuntimeException例如NullPointerException

What you're looking to do: 您要做什么:

  • Take in an integer input 接受整数输入
  • If the user enters a non-integer, tell them they need to enter an integer 如果用户输入非整数,则告诉他们他们需要输入整数
  • Keep doing this while userNth < 1 || userNth > piDecimals userNth < 1 || userNth > piDecimals时继续执行此userNth < 1 || userNth > piDecimals userNth < 1 || userNth > piDecimals . userNth < 1 || userNth > piDecimals

To that, we should look to get the right exception thrown by parsing the input as a string first , then as an Integer : 为此,我们应该通过首先将输入解析为字符串, 然后解析为Integer抛出正确的异常:

try {
    System.out.println("Pi to the number of decimal places:");
    userNth = Integer.parseInt(in.nextLine());
} catch (NumberFormatException e) {
    System.out.println("Error: Enter a number between 1 and 100");
    // You have to set this value to something so that userNth is defined!
    userNth = Integer.MAX_VALUE;
}

The other part to this is that you have to decide what message you show if userNth > 1 && userNth < piDecimals , since your try...catch isn't going to cover that. 另一部分是,如果userNth > 1 && userNth < piDecimals ,则必须决定显示什么消息,因为try...catch不会覆盖该内容。 This, I leave as an exercise for the reader. 这,我留给读者练习。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM