异常的概念
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。
比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出java.lang.ArithmeticException的异常。
异常的分类
检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
异常体系
异常.pngJava处理异常的方法
方法1:捕获异常(try-catch)
当抛出一个异常时,可以在try-catch块中捕获它并进行处理。
捕获异常的格式
try{
可能发生异常的代码块
}catch(可以捕获的异常1){
处理异常1的代码
}catch(可以捕获的异常2){
处理异常2的代码
}finally{
处理完所有异常后一定会执行的代码。
在这里注意的事。如果在这里没有出现异常,最终也会执行这行代码
}
实例:
public class Exception1 {
public static void main(String[] args) {
//方法1:捕获异常
int a = 0;
int b = 20;
FileReader fr = null;
try {
int c = b/a;
}catch (ArithmeticException e){
System.out.println(e.getMessage());
}
}
}
在上面的代码中,由于a的值为0,不能当分母,所以就会抛出一个"ArithmeticException"异常,在这里我们使用try-catch语块来处理异常,会在控制台输出相关异常信息。
若执行try块的过程中没有发生异常,则跳过catch子句。若是出现异常,try块中剩余语句不再执行。开始逐步检查catch块,判断catch块的异常类实例是否是捕获的异常类型。匹配后执行相应的catch块中的代码。如果异常没有在当前的方法中被捕获,就会被传递给该方法的调用者。这个过程一直重复,直到异常被捕获或被传给main方法(交给JVM来捕获)。
捕获异常的顺序
一个通用父类可以派生出各种异常类,如果一个catch块可以捕获一个父类的异常对象,它就能捕获那个父类的所有子类的异常对象。如果捕获的是多个同类型异常,则子类异常在前,父类异常在后,不然会导致编译错误。这是因为父类异常囊括了子类异常,如果父类异常在前,子类异常永远捕获不到,导致有时候无法准确描述错误信息。
try {
File f =new File("C:\\ProgramFile\\test.txt");
FileInputStream fis = new FileInputStream(f);
} catch (FileNotFoundException e) { //子类异常
e.printStackTrace();
} catch(IOException ie) { //父类异常
ie.printStackTrace();
} catch(Exception e) { //基类运行时异常
e.printStackTrace();
}
方法2:抛出异常(throw)
如果代码可能会引发某种错误,可以创建一个合适的异常类实例并抛出它,这就是抛出异常。如下所示:
public class Exception1 {
public static void main(String[] args) {
/**方法2的调用*/
try {
TException.test();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
/**方法2:使用throws抛出异常 如果有多个异常可以用逗号隔开,或者异常太多,可以直接抛出Exception*/
class TException {
public static void test() throws FileNotFoundException {
FileReader fr = new FileReader("");
}
public static void test3()throws PXDException{
//.....
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
StackTraceElement e =stackTrace[2];
String detail = e.getFileName()+"->"+e.getMethodName()+"->"+e.getLineNumber();
throw new LJRException("自己的异常类:无所作为"+detail);
}
}
自定义异常
/**自定义异常 1.提供一个有参数构造方法和一个无参数的构造方法*/
class LJRException extends Exception{
public LJRException(){
}
public LJRException(String s){
super(s);
}
}
说明:
/**
* 异常处理 错误:error
*
* 处理运行过程中出现的不可控的错误 使程序更健壮
* try{执行的代码 可能出现的异常 一旦出现异常,系统自动为我们创建一个异常对象 并抛出}
* catch(异常的类型 e){如果需要自己处理就catch}
* **如果有多个异常 就使用多个catch来捕获异常
* **如果有多个异常 catch的顺序是从小到大
* **如果异常出现,在try代码块里后面的代码将不会执行
* 当特殊情况出现了,自己可以选择抛出异常
*/
注意:
1.try、catch和finally都不能单独使用,只能是try-catch、try-finally或者try-catch-finally。
2.try语句块监控代码,出现异常就停止执行下面的代码,然后将异常移交给catch语句块来处理。
3.finally语句块中的代码一定会被执行,常用于回收资源 。
4.throws:声明一个异常,告知方法调用者。
5.throw :抛出一个异常,至于该异常被捕获还是继续抛出都与它无关。
异常相关面试题
1、try{} 里有一个 return 语句,那么紧跟在这个 try 后的 finally{} 里的 code 会不会被执行,什么时候被执行,在 return 前还是后?
答案:会执行,在方法返回调用者前执行。
2、Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?
答:Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果系统会抛出(throw)一个异常对象,可以通过它的类型来捕获(catch)它,或通过总是执行代码块(finally)来处理;try用来指定一块预防所有异常的程序;catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;throw语句用来明确地抛出一个异常;throws用来声明一个方法可能抛出的各种异常(当然声明异常时允许无病呻吟);finally为确保一段代码不管发生什么异常状况都要被执行;try语句可以嵌套,每当遇到一个try语句,异常的结构就会被放入异常栈中,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,异常栈就会执行出栈操作,直到遇到有处理这种异常的try语句或者最终将异常抛给JVM。
3、运行时异常与受检异常有何异同?
答:异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。异常和继承一样,是面向对象程序设计中经常被滥用的东西,在Effective Java中对异常的使用给出了以下指导原则:
- 不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
- 对可以恢复的情况使用受检异常,对编程错误使用运行时异常
- 避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
- 优先使用标准的异常
- 每个方法抛出的异常都要有文档
- 保持异常的原子性
- 不要在catch中忽略掉捕获到的异常
4、列出一些你常见的运行时异常?
答:
- ArithmeticException(算术异常)
- ClassCastException (类转换异常)
- IllegalArgumentException (非法参数异常)
- IndexOutOfBoundsException (下标越界异常)
- NullPointerException (空指针异常)
5.try-catch-finally-return执行顺序?
1.不管是否有异常产生,finally块中代码都会执行
2.当try和catch中有return语句时,finally块仍然会执行
3.finally是在return后面的表达式运算执行的,所以函数返回值在finally执行前确定的,无论finally中的代码怎么样,返回的值都不会改变,仍然是之前return语句中保存的值
4.finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值
6.Java异常类的重要方法是什么?
1.异常及其所有子类不提供任何特定方法,并且所有方法都在基类Throwable中定义。
2.String getMessage():此方法返回消息String of Throwable,并且可以在通过构造函数创建异常时提供消息。
3.String getLocalizedMessage():提供此方法,以便子类可以覆盖它以向调用程序提供特定于语言环境的消息。此方法getMessage()的可抛出类实现只是使用方法来返回异常消息。
4.synchronized Throwable getCause() :此方法返回异常的原因或null id,原因未知。
5.String toString():此方法以String格式返回有关Throwable的信息,返回的String包含Throwable类和本地化消息的名称。
6void printStackTrace() :此方法将堆栈跟踪信息打印到标准错误流,此方法已重载,我们可以将PrintStream或PrintWriter作为参数传递,以将堆栈跟踪信息写入文件或流。
网友评论