Java 提供了一种健壮且面向对象的方法来处理称为 Java异常处理的异常情况。
异常是在程序执行期间可能发生的错误事件,它会破坏其正常流程。异常可能源于各种情况,例如用户输入的错误数据,硬件故障,网络连接故障等。
每当执行 Java 语句时发生任何错误,都会创建一个异常对象,然后 JRE尝试查找异常处理程序来处理该异常。如果找到了合适的异常处理程序,则将异常对象传递到处理程序代码以处理异常,称为捕获异常。如果未找到处理程序,则应用程序将异常抛出给运行时环境,并且 JRE 终止程序。
Java 异常处理框架仅用于处理运行时错误,异常处理框架不处理编译时错误。
java 异常处理中使用了四个关键字。
throws
关键字将其传播到其调用方方法。我们可以在 throws 子句中提供多个异常,它也可以与 main()方法一起使用。Throwable
是 Java 异常层次结构的父类,它有两个子对象– Error
和Exception
。异常进一步分为检查异常和运行时异常。Error是超出应用程序范围的特殊情况,无法预见并从中恢复,例如硬件故障,JVM 崩溃或内存不足错误。
Checked Exception 是我们可以在程序中预期并尝试从程序中恢复的异常情况,例如 FileNotFoundException。我们应该捕获该异常,并向用户提供有用的消息,并正确记录下来以进行调试。Exception
是所有 “检查的异常” 的父类。
Runtime Exception是由错误的编程引起的,例如,尝试从 Array 中检索元素。在尝试检索元素之前,我们应该首先检查数组的长度,否则它可能ArrayIndexOutOfBoundException
在运行时抛出。RuntimeException
是所有运行时异常的父类。
准备面试的同学有福了,为大家收集整理了最新的BATJ面试资料、面试视频攻略,有需要的可以在公众号:「Java 知己」,发送「面试」获取。
Exception及其所有子类均未提供任何特定方法,并且所有方法均在基类 Throwable 中定义。
getMessage()
方法即可返回异常消息。catch(IOException | SQLException | Exception ex){
logger.error(ex);
throw new MyException(ex.getMessage());
}
在大多数情况下,我们使用 finally 块只是为了关闭资源,有时我们忘记关闭它们并在资源耗尽时获取运行时异常。这些异常很难调试,我们可能需要调查使用该类型资源的每个位置,以确保我们将其关闭。因此,java 7 的改进之一是 try-with-resources,我们可以在 try 语句本身中创建资源,并在 try-catch 块内使用它。当执行从 try-catch 块执行时,运行时环境会自动关闭这些资源。具有这种改进的 try-catch 块示例为:
try (MyResource mr = new MyResource()) {
System.out.println("MyResource created in try-with-resources");
} catch (Exception e) {
e.printStackTrace();
}
1、检查异常应在代码中使用 try-catch 块进行处理,否则方法应使用 throws 关键字使调用者知道该方法可能抛出的检查异常。未经检查的异常不需要在程序中处理,也不需要在方法的 throws 子句中提及。
2.、Exception是所有Checked 异常的超类,而RuntimeException
是所有Unchecked 的异常的超类。请注意,RuntimeException 是 Exception 的子类。
3、Checked 异常是需要在代码中处理的错误方案,否则您将获得编译时错误。例如,如果您使用 FileReader 读取文件,则可能会抛出该文件FileNotFoundException
,我们必须将其在 try-catch 块中捕获,或再次将其抛出给调用方方法。Unchecked 异常通常是由不良的编程引起的,例如,在调用对象引用中的方法而不确保其不为 null 时,会引发 NullPointerException。例如,我可以编写一种方法来删除字符串中的所有元音。确保不传递空字符串对象是调用者的责任。我可能会更改处理这些情况的方法,但理想情况下,调用方应注意这一点。
throws 关键字与方法一起使用,以声明该方法可能抛出的异常,而 throw 关键字用于中断程序流,并将异常对象移交给运行时进行处理。
我们可以扩展Exception
类或它的任何子类来创建我们的自定义异常类。自定义异常类可以具有自己的变量和方法,可用于将错误代码或其他与异常相关的信息传递给异常处理程序。
自定义异常的一个简单示例如下所示。
package com.journaldev.exceptions;
import java.io.IOException;
public class MyException extends IOException {
private static final long serialVersionUID = 4664456874499611218L;
private String errorCode="Unknown_Exception";
public MyException(String message, String errorCode){
super(message);
this.errorCode=errorCode;
}
public String getErrorCode(){
return this.errorCode;
}
}
Java 中的 OutOfMemoryError 是 java.lang.VirtualMachineError 的子类,当 JVM 堆内存不足时,它会被 JVM 抛出。我们可以通过修改 java 选项提供更多内存来解决此错误。
$>java MyProgram -Xms1024m -Xmx1024m -XX:PermSize=64M -XX:MaxPermSize=256m
一些常见的主线程异常情况是:
final 和 finally 是 Java 中的关键字,而 finalize 是一种方法。
在这三个中,只有finally 与 Java 异常处理有关。
当 main()方法引发异常时,Java Runtime 将终止程序并在系统控制台中打印异常消息和堆栈跟踪。
我们可以有一个空的 catch 块,但这是最糟糕的编程示例。我们永远不应该有空的 catch 块,因为如果异常被该块捕获,我们将没有有关该异常的信息,调试它将是一场噩梦。至少应该有一条日志记录语句,以将异常详细信息记录在控制台或日志文件中。
与 Java 异常处理有关的一些最佳实践是:
在这里,我们将研究与 Java 异常相关的一些编程问题。
1). 下面的程序有什么问题?
package com.journaldev.exceptions;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestException {
public static void main(String[] args) {
try {
testExceptions();
} catch (FileNotFoundException | IOException e) {
e.printStackTrace();
}
}
public static void testExceptions() throws IOException, FileNotFoundException{
}
}
上面的程序无法编译,并且您会收到错误消息,“The exception FileNotFoundException is already caught by the alternative IOException”。这是因为 FileNotFoundException 是 IOException 的子类,有两种方法可以解决此问题。
第一种方法是对两个异常都使用单个 catch 块。
try {
testExceptions();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
另一种方法是从多捕获块中删除 FileNotFoundException。
try {
testExceptions();
}catch (IOException e) {
e.printStackTrace();
}
您可以根据情况选择任何一种方法。
2). 下面的程序有什么问题?
package com.journaldev.exceptions;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.xml.bind.JAXBException;
public class TestException1 {
public static void main(String[] args) {
try {
go();
} catch (IOException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
}
}
public static void go() throws IOException, JAXBException, FileNotFoundException{
}
}
该程序将编译错误,因为 FileNotFoundException 是 IOException 的子类,因此 FileNotFoundException 的 catch 块不可访问,并且您将收到错误消息 “ Unreachable catch block for FileNotFoundException. It is already handled by the catch block for IOException”。
您需要修复 catch 块顺序才能解决此问题。
try {
go();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
}
请注意,JAXBException 与 IOException 或 FileNotFoundException 不相关,可以放置在以上 catch 块层次结构中的任何位置。
3). 下面的程序有什么问题?
package com.journaldev.exceptions;
import java.io.IOException;
import javax.xml.bind.JAXBException;
public class TestException2 {
public static void main(String[] args) {
try {
foo();
} catch (IOException e) {
e.printStackTrace();
}catch(JAXBException e){
e.printStackTrace();
}catch(NullPointerException e){
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
}
public static void foo() throws IOException{
}
}
该程序将无法编译,因为 JAXBException 是一个已检查的异常,并且 foo()方法应抛出此异常以捕获调用方法。您将收到错误消息 “ JAXBException 无法访问的捕获块。不会从 try 语句主体中引发此异常。
要解决此问题,您将必须删除 JAXBException 的 catch 块。
注意,捕获 NullPointerException 是有效的,因为它是未经检查的异常。
4). 下面的程序有什么问题?
package com.journaldev.exceptions;
public class TestException3 {
public static void main(String[] args) {
try{
bar();
}catch(NullPointerException e){
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
foo();
}
public static void bar(){
}
public static void foo() throws NullPointerException{
}
}
这是一个技巧性的问题,代码没有问题,它将成功编译。我们总是可以捕获 Exception 或任何未经检查的异常,即使它不在方法的 throws 子句中也是如此。
同样,如果方法(foo)在 throws 子句中声明未经检查的异常,则在程序中处理该异常不是强制性的。
5). 下面的程序有什么问题?
package com.journaldev.exceptions;
import java.io.IOException;
public class TestException4 {
public void start() throws IOException{
}
public void foo() throws NullPointerException{
}
}
class TestException5 extends TestException4{
public void start() throws Exception{
}
public void foo() throws RuntimeException{
}
}
上面的程序无法编译,因为子类中的start()方法签名不同。要解决此问题,我们可以将子类中的方法特性更改为与超类完全相同,也可以从子类方法中删除throws子句,如下所示。
@Override
public void start(){
}
6). 下面的程序有什么问题?
package com.journaldev.exceptions;
import java.io.IOException;
import javax.xml.bind.JAXBException;
public class TestException6 {
public static void main(String[] args) {
try {
foo();
} catch (IOException | JAXBException e) {
e = new Exception("");
e.printStackTrace();
}catch(Exception e){
e = new Exception("");
e.printStackTrace();
}
}
public static void foo() throws IOException, JAXBException{
}
}
上面的程序无法编译,因为多捕获块中的异常对象是最终对象,我们无法更改其值。由于“无法分配多捕获块的参数e”,将导致编译时错误。
我们必须删除对新异常对象的“ e”分配以解决此错误。
“不积跬步,无以至千里”,希望未来的你能:有梦为马 随处可栖!加油,少年!
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。