当前位置: 首页 > 科技观察

Java异常处理的9个最佳实践

时间:2023-03-13 12:09:51 科技观察

在Java中,异常处理是一件很麻烦的事情。初学者很难理解,即使是有经验的开发人员也需要很长时间才能决定是否应该处理和抛出异常。因此,许多开发团队都同意一些处理异常的原则。如果您是团队的新手,您可能会惊讶于他们商定的规则可能与您习惯的规则不同。但是,有许多最佳实践规则被大多数团队所接受。这里有9个重要的约定,可帮助您学习或改进异常处理。1、在Finally中清理资源或者使用Try-With-Resource特性大多数情况下,资源在try代码块中使用后需要关闭,比如InputStream。在这些情况下,一个常见的错误是在try块的末尾关闭资源。问题是这段代码只有在没有抛出异常时才有效。try代码块里面的代码会正常执行,可以正常关闭资源。但是,使用try代码块是有原因的。一般会调用一个或多个可能抛出异常的方法。而且,你自己可能会抛出异常,这意味着代码可能没有执行到try代码块的末尾***部分。因此,您不会关闭该资源。因此,您应该将清理代码放在finally中,或者使用try-with-resource功能。A。使用finally代码块与前面几行中的try代码块不同,finally代码块将始终被执行。无论try代码块是否执行成功,或者在catch代码块中处理异常后,它都会执行。因此,您可以确保清理所有打开的资源。b.Java7的Try-With-Resource语法的另一种替代方法是try-with-resource语法。我在IntroductiontoJavaExceptionHandling中更详细地介绍了它。如果您的资源实现了AutoCloseable接口,则可以使用此语法。大多数Java标准资源都继承自该接口。当你在try子句中打开一个资源时,该资源将在try代码块执行后或异常处理后自动关闭。2.优先考虑明确的例外情况。抛出的异常越明确越好。永远记住,几个月后你的同事或你会调用你的方法并处理异常。因此,有必要确保向他们提供尽可能多的信息。这样你的API就更容易理解了。您的方法的调用者可以更好地处理异常并避免额外检查。因此,请始终尝试找到最适合您的异常的类,例如抛出NumberFormatException而不是IllegalArgumentException。避免抛出不明确的异常。3.记录指定的异常无论何时在方法签名中指定异常,都应该在Javadoc中记录它。这与之前的最佳实践具有相同的目标:向调用者提供尽可能多的信息,以便避免或处理异常。因此,请务必在您的Javadoc中添加@throws声明并描述可能导致异常的条件。4.用描述性消息抛出异常的最佳实践背后的想法与前两者相似。但是这一次,您没有将信息提供给方法的调用者。每个必须了解在日志文件或监视工具中报告异常时发生了什么的人都可以阅读异常消息。因此,应尽可能准确地描述问题并提供最相关的信息以了解异常事件。不要误会我的意思,你不必写一段话。但你也应该用1-2个简短的句子解释异常的原因。这有助于您的运营团队了解问题的严重性,还可以让您更轻松地分析任何服务事件。如果抛出一个特定的异常,它的类名很可能已经描述了错误。因此,您不需要提供很多额外信息。一个很好的例子是NumberFormatException。当您提供错误格式的字符串时,它会被java.lang.Long类的构造函数抛出。NumberFormatException类的名称已经告诉您此类问题。它的消息说只需要提供导致问题的输入字符串。如果异常类的名称不具有表达性,则需要在消息中提供所需的信息。17:17:26,386ERRORTestExceptionHandling:52-java.lang.NumberFormatException:Forinputstring:"xyz"5.优先捕获特定异常大多数IDE可以帮助您实施此最佳实践。当您尝试首先捕获不太具体的异常时,它们会报告无法访问的代码块。但问题是只有第一个匹配到异常的catch块才会被执行。因此,如果您首先捕获IllegalArgumentException,您永远不会到达应该处理更具体的NumberFormatException的catch块,因为它是IllegalArgumentException的子类。特定的异常类总是首先被捕获,不太特定的catch块被添加到列表的末尾。您可以在下面的代码片段中看到此类try-catch语句的示例。第一个catch块处理所有NumberFormatException异常,第二个catch块处理所有不是NumberFormatException异常的IllegalArgumentException异常。6.不要捕获Throwable类Throwable是所有异常和错误的超类。你可以在catch子句中使用它,但你永远不应该那样做!如果在catch子句中使用Throwable,它不仅会捕获所有异常,还会捕获所有错误。JVM抛出错误,指示不应由应用程序处理的严重问题。典型的例子是OutOfMemoryError或StackOverflowError。两者都是由应用程序无法控制的条件引起的,无法处理。所以,***不要捕获Throwable,除非你确定你处于可以处理错误的特殊情况。7.不要忽略异常你有没有分析过只执行了用例第一部分的错误报告?这通常是由于忽略了异常。开发人员可能非常确定它永远不会被抛出并添加一个不处理它或记录它的catch块。当您发现该块时,您甚至可能会在其中找到“这永远不会发生”的注释。嗯,你可能正在分析一个不可能的问题。所以,请不要忽略任何异常。您不知道代码将来会如何更改。有人可能会删除阻止异常的验证,而不会意识到它会导致问题。或者抛出异常的代码已更改,现在抛出同一类的多个异常,并且调用代码不会阻止所有异常。您至少应该写一条日志消息,告诉每个人发生了这件不可思议的事情,需要有人检查一下。8.不要记录和抛出错误这可能是本文中最常被忽视的最佳实践。您可以找到许多代码片段,甚至一些代码库,在这些代码库中捕获、记录并重新抛出异常。在异常发生时记录异常,然后重新抛出异常,以便调用者可以适当地处理它,这可能感觉很直观。但是它会为同一个异常重复写入多条错误消息。17:44:28,945ERRORTestExceptionHandling:65-java.lang.NumberFormatException:Forinputstring:"xyz"Exceptioninthread"main"java.lang.NumberFormatException:Forinputstring:"xyz"atjava.lang.NumberFormatException.forInputString(NumberFormatException.java:65)。lang.Long.parseLong(Long.java:589)在java.lang.Long.(Long.java:965)在com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)在com.stackify.example。测试异常处理。main(TestExceptionHandling.java:58)附加消息也没有添加任何信息。如最佳实践#4中所述,异常消息应描述异常事件。堆栈跟踪告诉您异常是在哪个类、方法和行中抛出的。如果您需要添加额外的信息,您应该捕获异常并将其包装在自定义信息中。但一定要遵循最佳实践#9。所以,只捕获你想要处理的异常。否则,在方法签名中指定它并让调用者处理它。9.不要使用封装的异常类有时候,最好捕获一个标准的异常,然后封装成一个自定义的异常。一个典型的例子是应用程序或框架特定的业务异常。允许你添加一些额外的信息,你也可以为你的异常类实现一个特殊的处理。执行此操作时,请确保将原始异常设置为原因(注意:请参考下面代码NumberFormatExceptione中的原始异常e)。Exception类提供了一种特殊的构造函数方法,该方法将Throwable作为参数。此外,您将丢失堆栈跟踪和原始异常的消息,这将使分析导致异常的异常事件变得困难。总结如您所见,抛出或捕获异常时需要考虑许多不同的事情,其中??大部分旨在提高代码的可读性或API的可用性。异常通常是一种异常处理技术,也是一种通信媒介。因此,为了更好地与同事合作,团队必须制定一套最佳实践和规则,只有这样团队成员才能理解这些共同的概念并将其运用到工作中。