作为一个编程新手,异常处理的概念可能很难让你理解。并不是说概念本身很难理解,而是术语可以让它看起来比实际更先进。而且它的功能非常强大,很容易被滥用。
在本文中,您将了解什么是异常,它们为什么重要,如何使用它们,以及要避免的常见错误。大多数现代语言都有某种类型的异常处理,因此如果您从Java开始,您可以随身携带这些技巧中的大部分。
在Java中,异常是指在应用程序运行期间发生异常(或“异常”)的对象。抛出这样的异常,这基本上意味着创建了一个异常对象(类似于“引发”错误的方式)。
这样做的好处是,您可以捕获抛出的异常,这样您就可以处理异常情况,并允许应用程序继续运行,就好像没有什么问题一样。例如,C中的空指针可能会使应用程序崩溃,而Java允许抛出并捕获
NullPointerException在空变量有可能导致崩溃之前。
请记住,异常只是一个对象,但有一个重要特征:它必须从
Exception类或其任何子类
Exception. 虽然Java有各种各样的内置异常,但是如果您愿意,也可以创建自己的异常。一些最常见的Java异常包括:
那么当抛出异常时会发生什么呢?
首先,Java在immediate方法中查看是否有处理抛出的异常类型的代码。如果处理程序不存在,它会查看调用当前方法的方法,以查看那里是否存在句柄。如果没有,它将查看调用该方法的方法,然后查看下一个方法,等等。如果没有捕获异常,应用程序将打印堆栈跟踪,然后崩溃。(实际上,这比简单的崩溃更为微妙,但这是一个超出本文范围的高级主题。)
堆栈跟踪是Java在查找异常处理程序时遍历的所有方法的列表。堆栈跟踪如下所示:
Exception in thread "main" java.lang.NullPointerException at com.example.myproject.Book.getTitle(Book.java:16) at com.example.myproject.Author.getBookTitles(Author.java:25) at com.example.myproject.Bootstrap.main(Bootstrap.java:14)我们可以从中收获很多。首先,抛出的异常是
NullPointerException. 它发生在
getTitle()第16行的方法书籍.java. 该方法是从
getBookTitles()第25行作者.java. 该方法是从
main()第14行引导.java. 如您所见,了解所有这些使调试更容易。
但是,异常的真正好处是,您可以通过捕获异常、纠正错误并在不崩溃的情况下恢复应用程序来“处理”异常情况。
假设你有
someMethod()它接受一个整数并执行一些逻辑,如果整数小于0或大于100,这些逻辑可能会中断。这可能是抛出异常的好地方:
public void someMethod(int value) { if (value < 0 || value > 100) { throw new IllegalArgumentException为了捕捉这个异常,您需要转到
someMethod()调用并使用try-catch块:
public void callingMethod() { try { someMethod(200); someOtherMethod(); } catch (IllegalArgumentException e) { // handle the exception in here } // ...}try块中的所有内容都将按顺序执行,直到抛出异常为止。一旦抛出异常,将跳过所有后续语句,应用程序逻辑立即跳转到catch块。
在我们的示例中,我们输入try块并立即调用
someMethod(). 因为200不在0和100之间
IllegalArgumentException被抛出。这将立即结束执行
someMethod(),跳过try块中的其余逻辑(
someOtherMethod()从不调用),并在catch块内恢复执行。
如果我们打电话会怎么样
someMethod(50)相反呢?这个
IllegalArgumentException不会被扔的。
someMethod()会正常执行。try块将正常执行,调用
someOtherMethod()当someMethod()完成时。什么时候?
someOtherMethod()结束时,将跳过catch块
callingMethod()会继续。
请注意,每个try块可以有多个catch块:
public void callingMethod() { try { someMethod(200); someOtherMethod(); } catch (IllegalArgumentException e) { // handle the exception in here } catch (NullPointerException e) { // handle the exception in here } // ...}还要注意,还存在一个可选的finally块:
public void method() { try { // ... } catch (Exception e) { // ... } finally { // ... }}finally块中的代码总是被执行,不管发生什么。如果try块中有return语句,那么finally块将在返回方法之前执行。如果在catch块中抛出另一个异常,那么finally块将在抛出异常之前执行。
当有对象需要在方法结束前清理时,应该使用finally块。例如,如果您在try块中打开了一个文件,然后抛出了一个异常,那么finally块允许您在离开方法之前关闭该文件。
请注意,可以使用finally块而不使用catch块:
public void method() { try { // ... } finally { // ... }}这允许您在允许抛出的异常向上传播方法调用堆栈的同时执行任何必要的清理(即,您不想在此处处理异常,但仍需要首先清理)。
与大多数语言不同,Java区分了检查异常和未检查异常(例如,C#只有未检查的异常)。必须在抛出异常的方法中捕获选中的异常,否则代码将无法编译。
要创建选中的异常,请从
Exception. 要创建未检查的异常,请从
RuntimeException.
任何抛出选中异常的方法都必须使用throws关键字在方法签名中表示该异常。因为Java是内置的
IOException是选中的异常,以下代码将不会编译:
public void wontCompile() { // ... if (someCondition) { throw new IOException(); } // ...}必须首先声明它引发选中的异常:
public void willCompile() throws IOException { // ... if (someCondition) { throw new IOException(); } // ...}请注意,方法可以声明为引发异常,但不会实际引发异常。即便如此,仍然需要捕获异常,否则代码将无法编译。
什么时候应该使用选中或未选中的异常?
官方Java文档中有一个关于这个问题的页面。它用一条简洁的经验法则总结了这一区别:“如果可以合理地期望客户机从异常中恢复,那么就将其设置为检查过的异常。如果客户端无法执行任何操作从异常中恢复,请将其设置为未检查的异常。“
但是这个指导方针可能已经过时了。一方面,经过检查的异常确实会产生更健壮的代码。另一方面,没有其他语言像Java那样检查异常,这说明了两件事:第一,这个特性对其他语言来说不够有用,无法窃取它;第二,你完全可以不用它们。另外,选中的异常不能很好地处理Java8中引入的lambda表达式。
例外是有用的,但很容易被滥用和滥用。以下是一些提示和最佳实践,可以帮助您避免把它们弄得一团糟。
现在您应该对异常有足够的了解,了解它们是什么,为什么使用它们,以及如何将它们合并到您自己的代码中。如果你不完全理解这个概念,那没关系!它花了我一段时间才在我的脑子里“咔嚓”一声,所以你不必着急。慢慢来。
有什么问题吗?你知道我遗漏了其他与异常相关的提示吗?在下面的评论中分享它们!
...误会产生意外的结果,也可能会终止程序的执行。因此,正确地检测和管理错误,才能正确地执行程序。错误可以有两种类型。它们是编译时错误和运行时错误。当有语法错误时,由Java编译器指示。这些被称为编译时错误。一...
...选中的异常中,必须处理异常。如果不进行处理,程序的正确流将终止,并且不会生成类文件。可以使用try,catch块来处理错误。 图01:检查的异常处理 根据上述内容,FileReader从文件中读取数据。text1.txt文件在指定位置不存在...
...。为此,可以使用final。在编程中,可能会有错误,为了正确地执行程序,处理这些错误是很重要的。finalize是由垃圾回收器调用的方法。因此,所有这些术语都有不同的含义。final是一个关键字,用于防止更改变量、避免方法重...
... 作为一个Java程序员,您应该完全理解Java虚拟机是如何工作的,以及为什么它允许跨平台开发。您还应该熟悉核心Java概念,例如如何在Java中使用异常。你也可以用Java玩得很开心---用Java和处理技术创造出惊人的网络摄像...
...这些服务提供了一个集中的目录。在本文中,我们将学习如何实现一个服务器来公开对象,以及如何实现一个客户端来调用服务器上的方法,以及如何在RMI注册表中注册和查找服务。 ...
... 下面的代码示例演示了如何包装异常。方法\u 1()在其主体中抛出一个SQLException。要使代码正确编译,必须声明抛出异常。 ...
...果的实时视频幻灯片。除了翻转实时视频外,您还将学习如何调整其大小和颜色,以及如何使其跟随鼠标光标。 ...