7.异常
1.什么是异常,java提供异常处理机制有什么用?
以下程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常
java语言是很完善的语言,提供了异常的处理方式,以下程序执行过程中出现了不正常情况
java把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对程序进行修改,让程序更加的健壮。
什么是异常
2.以下程序执行控制台出现了
Exception in thread “main” java. Lang ArithmeticException : by zero
at com. bipowernode javase exception.ExceptionTest01 main( Exception Testo1 java: 14)
这个信息被我们称为:异常信息。这个信息是JVM打印的。
一.实例
public class ExceptionTest01 {
public static void main(String[] args) {
int a=10;
int b=0;
//实际上JVM在执行到此处的时候,会new异常对象: new ArithmeticException("/ by zero")
//并且JVM将new的异常对象抛出,打印输出信息到控制台了。
int c=a/b;
}
}
Exception in thread “main” java.lang.ArithmeticException: / by zero
at Test01.main(Test01.java:7)
二.异常的继承结构图
三.编译时异常和运行时异常的区别
编译时异常一般发生的概率比较高。
举个例子:
你看到外面下雨了,倾盆大雨的。
你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。
而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。
“拿一把伞”就是对“生病异常”发生之前的一种处理方式。
对于一些发生概率较高的异常,需要在运行之前对其进行预处理。
运行时异常一般发生的概率比较低。
举个例子:
小明走在大街上,可能会被天上的飞机轮子砸到。
被飞机轮子砸到也算一种异常。
但是这种异常发生概率较低。
在出门之前你没必要提前对这种发生概率较低的异常进行预处理。
如果你预处理这种异常,你将活的很累。
假设你在出门之前,你把能够发生的异常都预先处理,你这个人会更加
的安全,但是你这个人活的很累。
假设java中没有对异常进行划分,没有分为:编译时异常和运行时异常,
所有的异常都需要在编写程序阶段对其进行预处理,将是怎样的效果呢?
首先,如果这样的话,程序肯定是绝对的安全的。
但是程序员编写程序太累,代码到处都是处理异常的代码。
再次强调:所有异常都是发生在运行阶段的
四.异常的两种处理方式
Java语言中对异常的处理包括两种方式:
第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。
谁调用我,我就抛给谁。抛给上一级。
第二种方式**:使用try…catch语句进行异常的捕捉。**
这件事发生了,谁也不知道,因为我给抓住了。
举个例子:
我是某集团的一个销售员,因为我的失误,导致公司损失了1000元,
“损失1000元”这可以看做是一个异常发生了。我有两种处理方式,
第一种方式:我把这件事告诉我的领导【异常上抛】
第二种方式:我自己掏腰包把这个钱补上。【异常的捕捉】
张三 --> 李四 —> 王五 --> CEO
思考:
异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要
对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。
1.8、注意**:Java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续
向上抛,抛给了调用者JVM**,JVM知道这个异常发生,只有一个结果。终止java程序的执行。
五.方法声明的地方使用throws
/*以下代码报错的原因是什么?
因为 dosome()方法声明位置上使用了: throws ClassNotFoundException
而ClassNot FoundException是编译时异常。必须编写代码时处理,没有处理
编译器报错。*/
public class ExceptionTest04 {
public static void main(String[] args) {
//main方法中调用 dosome()方法
//因为 dosome()方法声明位置上有: throws ClassNotFoundException
//我们在调用Some()方法的时候必须对这种异常进行预先的处理。
//如果不处理,编译器就报错。
//dosome();
}
/*
dosome方法在方法声明的位置上使用了: throws ClassNot FoundException
这个代码表示 dosome()方法率执行过程中,有可能会出现 LassNotFoundException异常。
叫做类没找到异常。这个异常值接父类是: Exception,所 ClassNotFoundException属于编译时异常
throws ClassNotFoundException*/
public static void dosome() throws ClassNotFoundException{
System.out.println("do some");
}
}
六.异常捕捉和上报的联合使用
1.文件找得到
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*处理异常的第一种方式:
在方法声明的位置上使用 throws关键字抛出,谁调用我这个方法,我就抛给谁。
抛给调用者来处理。
这种处理异常的态度:上报。
处理异常的第二种方式:
使用try.. catch语句对异常进行捕捉。
这个异常不会上报,自己把这个事儿处理了。
异常抛到此处为止,不再上抛了*/
public class ExceptionTest06 {
/* 一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。
异常处理机制的作用就是增强程序的健壮性。怎么能做到,异常发生了也不影啊程序的执行。所以
一般main方法中的异常建认使用try., catch进行捉。main就不要继续上抛了。*/
public static void main(String[] args) {
try {
m1();
System.out.println("Hello World");
} catch (IOException e) {
System.out.println("文件不纯正,可能路径错误,也可能文件被删除");
}
}
public static void m1() throws IOException{
System.out.println("m1 begin");
m2();
System.out.println("m1 over");
}
/* throws 后面也可以抛出多个异常,但是后续还要处理那个classNotFoundException
public static void m2() throws FileNotFoundException,ClassNotFoundException {
m3();
}*/
/*
抛别的不行,抛 ClassCastException说明你还是没有FileNot FoundException进行处理
private static void m2() throws ClassCastExceptionf
抛 ileNot FoundException的父对象 EXception,这样是可以的。
Exception包括 ileNot FoundException*/
public static void m2() throws FileNotFoundException {
System.out.println("m2 begin");
m3();
System.out.println("m2 over");
}
public static void m3() throws FileNotFoundException {
/* 编译报错的原因是什么?
第-:这里调用了一个构造方法: FileInputstream( String name)
第二:这个构造方法的声明位置上有: throws FileNot FoundException
第三:通过类的继承结构看到: FileNotFoundException父类是 IOException, IOException的父类是 Exception
最终得知, FileNot FoundException是编译时异常
错误原因?编译时异常要求程序员编写程序阶段必须对它进行处理,不处理编译器就报错。
*/
// new FileInputStream("D:\\IDM\\Video\\app.asar");
//我们采用第一种处理方式:在方法声明的位置上使用throws继续上抛。
new FileInputStream("D:\\IDM\\Video\\app.asar");
System.out.println("如果以上代码异常,这里会执行嘛??不会");
}
}
m1 begin
m2 begin
m2 over
m1 over
Hello World
main over
2.文件找不到
new FileInputStream("D:\\IDM\\Video\\ap.asar");
如果以上代码异常,这里会执行嘛??不会m1 over m2 over main over都不会执行 马上跳到catch语句块中,所以并不会执行hellow world
m1 begin
m2 begin
文件不纯正,可能路径错误,也可能文件被删除
3.try catch深入
try语句块抛出异常时,其后的代码不会被执行,如果想继续执行剩余代码,可将剩余代码放在finally语句块中
深入try. catch
1、 catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型。
2、 catch可以写多个。建认 catch的时候,精确的一个一个处理。这样有利于程序的调闻。
3、 catch写多个的时候,从上到下,必须遵守从小到大。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest07 {
public static void main(String[] args) {
try{
//创建输入流
FileInputStream fis=new FileInputStream("D:\\study\\Java\\fuck\\作业.txt");
//读文件
fis.read();
} catch (FileNotFoundException e) {
System.out.println("文件不存在");
}catch (IOException e){
System.out.println("该文件报错了");
}
}
}
public class ExceptionTest07 {
public static void main(String[] args) {
try{
//创建输入流
FileInputStream fis=new FileInputStream("D:\\study\\Java\\fuck\\作业.txt");
//进行数学运算
System.out.println(100/0);
}
/*
catch (FileNotFoundException e) {
System.out.println("文件不存在");
}catch (IOException e){
System.out.println("该文件报错了");
}*/
//jdk8 新特性
catch(FileNotFoundException | java.lang.ArithmeticException | NullPointerException e){
System.out.println("文件不存在?数字异常?空指针异常?");
}
}
}
4.异常对象的常用方法
来自jdk1.8开发文档
getMessage
public String getMessage()
返回该错误的详细信息的字符串。
结果
这 Throwable实例的详细信息的字符串(可以 null)。
printStackTrace
public void printStackTrace()
打印到标准错误流这个异常和回溯。这种方法打印一个堆栈跟踪,这在错误输出流,是现场 System.err价值 Throwable对象。输出的第一行包含该对象的 toString()方法的结果。剩余的线代表的方法 fillInStackTrace()先前记录的数据。这些信息的格式依赖于实现
如何取得异常对象的具体信息,常用的方法主要有两种:
1.取得异常描述信息:getMessage()
2.取得异常的堆栈信息(比较适合于程序调试阶段):printStackTrace();
public class ExceptionTest08 {
/* 异常对亲有两个并常重要的方法:
获取异常简单的描述信息
String msg exception getMessage()
打印异常追踪的堆找信息
exception. printstackTrace();*/
public static void main(String[] args) {
/* 这里只是为了测getMessage()方法和pnintStackTrace()方法。
这里只是new异常对象,但是没有将异常对抛.JVM会认为这是一个普通的java对象。*/
NullPointerException e=new NullPointerException("空指针异常");
//获取异常筒单描述信息:这个信息实际上就是构造方法上面String参数
String s=e.getMessage();//空指针异常
System.out.println(s);
/* 打印异常堆找信息
java后台打印异常堆找追踪信息的时候,采用了异步线程的方式打印
所以不一定空指针异常还是那个堆栈信息先后出来不一定*/
e.printStackTrace();
}
}
空指针异常
java.lang.NullPointerException: 空指针异常
at ExceptionTest06.main(ExceptionTest06.java:10)
实战
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/*异常对象的两个方法
String msg = e.getMessageO
e printStackTrace();
我们以后查看异常的追踪信息,我们应该怎么看,可以快速的调试程序呢?
异常信息追踪信息,从上往下一行一行看
但是需要注意的是:SUN写的代码就不用看了(看包名就知道是自己的还是SUN的。)
主要的问题是出现在自己编写的代码上。*/
public class ExceptionTest09 {
public static void main(String[] args) {
try {
m1();
} catch (FileNotFoundException e) {
//获取异常简单描述信息
String msg=e.getMessage();
System.out.println(msg);
//打印异常堆找追踪信息!!!
//在实际的开发中,建议使用这个。养成好习惯
e.printStackTrace();
/* java.io.FileNotFoundException: D:\Tencent\QQLicense.tf (系统找不到指定的文件。)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)
at com.Exception.ExceptionTest09.m3(ExceptionTest09.java:21)
at com.Exception.ExceptionTest09.m2(ExceptionTest09.java:18)
at com.Exception.ExceptionTest09.m1(ExceptionTest09.java:15)
at com.Exception.ExceptionTest09.main(ExceptionTest09.java:9)
*/
}
//这里程序不耽误执行,很健壮(服务器不会遭到异常而宕机)
System.out.println("Hello World");
}
public static void m1() throws FileNotFoundException {
m2();
}
public static void m2() throws FileNotFoundException {
m3();
}
public static void m3() throws FileNotFoundException {
new FileInputStream("D:\\Tencent\\QQicense.rtf");
}
}
“C:\Program Files\Java\jdk-13.0.2\bin\java.exe” “-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.2\lib\idea_rt.jar=3418:C:\Program Files\JetBrains\IntelliJ IDEA 2020.2\bin” -Dfile.encoding=UTF-8 -classpath D:\Study\Javahomework\访问控制权限\out\production\访问控制权限 com.Exception.ExceptionTest09
D:\Tencent\QQicense.rtf (系统找不到指定的文件。)
Hello World
java.io.FileNotFoundException: D:\Tencent\QQicense.rtf (系统找不到指定的文件。)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.(FileInputStream.java:155)
at java.base/java.io.FileInputStream.(FileInputStream.java:110)
at com.Exception.ExceptionTest09.m3(ExceptionTest09.java:46)
at com.Exception.ExceptionTest09.m2(ExceptionTest09.java:43)
at com.Exception.ExceptionTest09.m1(ExceptionTest09.java:40)
at com.Exception.ExceptionTest09.main(ExceptionTest09.java:16)
Process finished with exit code 0
7.关于try… catch中的 finally子句
1、在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。finally子句必须和try一起出现,不能单独编写。
2、 finally语句通常使用在娜些情况下呢?
通常在 finally语句块中完成资源的释放/关闭。
因为 finally中的代码比较有保障。
即使try语句块中的代码出现异常, finally中代码也会正常执行。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest10 {
public static void main(String[] args) {
FileInputStream fis=null;
try {
fis=new FileInputStream("D:\\Tencent\\QQLicense.rtf");
//这里一定会出空指针异常
String s=null;
s.toString();
System.out.println("Hello World");
/* /流使用完需要关闭,因为流是占用资源的
/即使以上程序出现异常,流也必须要关闭!
/放在这里有可能流关不了。*/
// fis.close();
} catch (FileNotFoundException e) {
//因为上述文件路径有效这里并没有执行
e.printStackTrace();
} catch (NullPointerException e){
e.printStackTrace();
}finally {
try {
System.out.println("in work");
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
java.lang.NullPointerException
at com.Exception.ExceptionTest10.main(ExceptionTest10.java:14)
in work
public class ExceptionTest13 {
public static void main(String[] args) {
int i=100;
int result=m1(i);
System.out.println(result);
}
/* java语法规则(有一些规则是不能破坏的,一且这么说了,就必须这么做!):
java中有一条这样的规则
方法体中的代码必须遵循自上而下顺序次逐行执行(亘古不变的语法!)
java中还有一条语法规则
return语句一且执行,整个方法必须结束(互古不变的语法!)*/
//除非在try中写上System.exit(0);退出JVM虚拟机,否则finally中代码一定执行
//这里是因为创建了j局部变量,使得100
public static int m1(int i){
try{
return i;
}finally {
i++;
}
}
}
//反编译运行结果
/*public static int m()
{ int i =100;
int j=i;
i++;
return j;
Exception exception
exception;
i++
throw exception;
}
*/
100
final finally finalize有什么区别?
final关键字
final修饰的类无法继承
final修饰的方法无法覆盖
final修饰的变量不能重新厨值。
finally 关键字
积try-起联合使用。
finally语句块中的代码是必须执行的。
finalize 标识符
是一个0bject类中的方法名。
这个方法是由垃级回收器G C负责调用的。
8.自定义异常
Java中怎么自定义异常呢?
两步:
第一步:编写一个类继承Exception或者 RuntimeException
第二步:提供两个构造方法,一个无参数的,一个带有 String参数的。
死记硬背(sun公司的格式)
public class MyException extends Exception {
public MyException(){
}
public MyException(String s){
super(s);
}
}