-
什么是异常?java中提供异常处理机制有什么作用?
异常是程序在执行过程中出现的一些不正常情况;
异常能够提高程序的健壮性,java中提供了异常处理机制,能够将程序执行过程中发生的不正常情况打印到控制台,提醒程序员。异常信息由JVM打印。 -
异常在java中以什么形式存在?
异常在java中以类的形式存在,每一个异常类都可以创建异常对象。所有的异常类是从 java.lang.Exception 类继承的子类。异常发生了,底层一定会new一个异常对象出来。
public class TestException {
public static void main(String[] args) {
// 异常可以创建对象
NumberFormatException nfe = new NumberFormatException("数字格式化异常");
System.out.println(nfe);
int a = 10;
int b = 0;
int c = a/b; //实际上JVM执行到此处的时候会new异常对象,并且JVM将异常对象抛出,打印输出信息到控制台
System.out.println(c);
System.out.println(100/0);//new ArithmeticException(" / by zero")
}
}
- 异常类的层次
Object: Object下有Throwable(可抛出的),不管是异常还是错误都是可以抛出的
Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)
Exception下有两个分支:
Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常。),也被称为受检异常或者受控异常。
RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不管,都行。),也叫未受检异常或者非受控异常 - 编译时异常和运行时异常,都是发生在运行阶段。编译阶段异常是不会发生的。因为只有程序运行阶段才可以new对象。因为异常的发生就是new异常对象。
- 编译时异常和运行时异常的区别?
编译时异常一般发生的概率比较高。运行时异常一般发生的概率比较低。 - 假设java中没有对异常进行划分,没有分为:编译时异常和运行时异常,所有的异常都需要在编写程序阶段对其进行预处理,将是怎样的效果呢?
首先,如果这样的话,程序肯定是绝对的安全的。但是程序员编写程序太累,代码到处都是处理异常的代码。 - Java语言中对异常的处理包括两种方式:
第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。谁调用我,我就抛给谁。叫异常上抛。
第二种方式:使用try…catch语句进行异常的捕捉。捕捉后,后面的程序可以继续执行 - 注意:Java中异常发生之后如果一直上抛,最终抛给了main方法,如果不捕捉的话,main方法会自动向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止java程序的执行。
- 关于异常处理的两种方式,代码执行效果的差异
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class TestException {
public static void main(String[] args) {
try {//尝试执行m1方法
m1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 这里采用捕捉的方式,故下面这行代码会执行
System.out.println("main end");
}
public static void m1() throws FileNotFoundException{
System.out.println("m1begin");
m2();
// 这里继续上抛,下面这行代码不会执行
System.out.println("m1end");
}
public static void m2() throws FileNotFoundException {
System.out.println("m2begin");
FileInputStream fileInputStream = new FileInputStream("C:\\Proram Files");//路径不存在,出现FileNotFoundException异常
// 这里采用上抛的处理方式,故下面这行代码不会执行
System.out.println("m2end");
}
}
- 异常中的两个重要方法
/*异常有两个重要的方法*/
public class TestException01 {
public static void main(String[] args) {
// 这里虽然创建了异常对象,但是没有将异常抛出,JVM会认为只是一个普通的JVM对象
NumberFormatException nfe = new NumberFormatException("数字格式化异常");
String str1 = nfe.getMessage();//获取简单的描述信息
System.out.println(str1);
/*
throw nfe;//将异常抛出,JVM会中断程序
*/
nfe.printStackTrace();//打印异常堆栈信息,异常追踪信息,捕捉异常后通常写这个
}
}
- 关于try…catch中的finally子句:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestException02 {
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("C:\\important.txt");
String str = null;
str.toString();//这里会出现空指针异常,导致下面代码不会执行
// fileInputStream.close();//流使用完需要关闭,因为流是占用资源的
} catch (FileNotFoundException e) {//编译时异常
e.printStackTrace();
} catch (NullPointerException e) {//运行时异常
e.printStackTrace();
} finally {//一定会执行,通常完成资源的释放/关闭
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
try...finally
try不能单独使用*/
try {
System.out.println("");
return;//程序执行到这里之后,先执行finally语句块,再return结束方法
} finally {
System.out.println("就算try中有return语句,finally里的语句一样会执行");
}
}
}
有一个语句除外:
public class TestException03 {
public static void main(String[] args) {
try {
System.out.println("HelloWord");
System.exit(0);
} finally {
System.out.println("不会执行了");
}
}
}
- 试分析以下代码的执行结果:
public class TestException03 {
public static void main(String[] args) {
int result = m1();
System.out.println(result);
}
public static int m1() {
int i = 100;
try {
return i;
} finally {
i++;
}
}
}
结果是100;java中遵循方法体中的代码是自上而下依次执行的,return语句一旦执行,整个方法必须结束,也就是说return语句一定是方法中执行的最后一个语句,但finally里面的代码也一定会执行,而且先于return语句,为了遵循自上而下的执行原则,return返回的是没有经过++的i值。反编译效果如下:
public static int m1() {
int i = 100;
int j = i;
i++;
return j;
}
- java中自定义异常
1.编写一个类继承Exception或RuntimeException
2.提供两个构造方法,一个无参的,一个带有String参数的
public class MyException extends Exception {//编译时异常(继承RuntimeException为运行时异常)
public MyException() {
super();
}
public MyException(String string) {
super(string);
}
}
-
重写之后的方法不能比重写之前的方法抛出更多(更广)的异常(编译时异常),可以更少
-
总结
方法对程序执行过程中可能会出现的不正常情况,或者是超出意愿的事,对其视作异常处理,new出异常对象,将其上抛,如果创建的是编译时异常对象,则调用者必须对其进行处理,上抛或者捕捉,如果创建的是运行时异常对象,则调用者可以先不处理。 -
异常的应用场景
LengthException为自定义的异常类,如下代码为创建用户的方法,规定用户名的字符应在6到15之间,否则抛出异常。
public static User register(String str1,String str2) throws LengthException {
if (str1 == null || str1.length() > 14 || str1.length() < 6) {
throw new LengthException("用户名长度不规范,应在[6,15]个字符之间");
}
return new User(str1,str2);
}