异常
(1)、什么是异常?java提供异常处理机制有什么用?
程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常
Java语言是很完善的语言,提供了异常的处理方式,当程序执行过程中出现了不正常的情况,Java把该异常信息打印输出到控制台(JVM打印),共程序员参考,程序员看到异常信息之后,可以对程序进行修改,让程序更加的健壮。
package javaCoreTest;
public class ExceptionTest02 {
public static void main(String [] args) {
/*
* 程序执行到此处发生了java.lang.ArithmeticException: / by zero异常
* 底层new出了一个ArithmeticException异常对象,然后抛出了,由于是main方法
* 调用了100 / 0,所以这个异常ArithmeticException抛给了main方法,main方法
* 没有处理,将这个异常自动抛给了JVM,JVM最终终止程序的执行。
*/
System.out.println(100 / 0);
//这里的hello没有输出,没有执行
System.out.println("hello");
}
}
package javaCoreTest;
/*
* java语言中异常是以什么形式存在的?
* 1.异常在Java中以类的形式存在,每一个异常类都可以创建异常对象
*/
public class ExceptionTest01 {
public static void main(String [] args) {
//通过“异常类”实例化“异常对象”
NumberFormatException nfe = new NumberFormatException("数字格式化异常");
System.out.println(nfe);//java.lang.NumberFormatException: 数字格式化异常
//通过“异常类”创建“异常对象”
NullPointerException npe = new NullPointerException("空指针异常发生了");
System.out.println(npe);//java.lang.NullPointerException: 空指针异常发生了
int a = 10;
int b = 0;
//实际上JVM在执行到此处的时候,会new异常对象:new ArithmeticException("/by zero");
int c = a / b;
System.out.println(a + "/" + b + "=" + c);
}
}
(2)、异常的继承结构是怎样的?
使用UML图来描述继承结构
画UML图的工具:Rational Rose(收费)、starUML等
UML是一种统一建模语言、一种图标式语言
并不是只在java中使用,只要是面向对象的编程语言,都有UML
UML图可以描述类和类之间的关系,程序执行的流程,对象的状态等
Object
Object下有Throwable(可抛出的)
Throwale下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)
Exception下有两个分支:
Exception的直接子类:编译时异常【受检异常,受控异常】(要求程序员在编写程序阶段必须预先对这些异常进行处理)
RuntimeException:运行时异常【未受检异常,为受控异常】(在编写程序阶段程序员可以预先处理,也可以不管)
注:编译异常和运行异常都发生在运行阶段。编译时,异常必须在编译(编写)阶段预先处理,如果不处理编译器会报错,因此得名。所有异常都是在运行阶段发生的,因为只有程序运行阶段才可以new对象,异常的发生就是new异常对象。
编译时异常和运行时异常的区别?
**编译时异常发生的概率比较高
对于一些发生概率较高的异常,需要在运行之前对其进行预处理。
**运行时异常发生的概率比较低
(3)、java语言中对异常的处理包括两种方式:
-
第一种方式:在方法声明的位置上使用throws关键字,抛给上一级
-
第二种方式:使用try…catch语句进行异常的捕捉
try…catch:
-catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型。
-catch可以写多个,建议catch的时候,精确的一个一个处理,也可以是该异常类型的父类型。
-catch写多个的时候,从上到下,必须遵守从小到大。
package javaCoreTest;
public class ExceptionTest03 {
public static void main(String [] args) {
/*
* main()方法调用doSome方法,因为doSome方法声明位置上有throws ClassNotFoundException
* 我们在调用doSome方法时必须对这种异常进行预先的处理,如果不处理编译器就会报错
*/
//doSome();
}
/*
* 以下的方法在声明的位置上使用了:throws ClassNotFoundException
* 这个代码表明此方法在执行过程中,有可能会出现throws ClassNotFoundException异常
* 叫做类没有找到异常,这个异常的直接父类是:Exception,属于编译时异常
*/
public static void doSome() throws ClassNotFoundException {
System.out.println("doSome!!!");
}
}
package javaCoreTest;
public class ExceptionTest04 {
/*
* 处理异常的第一种方法:
* 在方法声明的位置上继续使用:throws,来完成异常的继续上抛,抛给调用者
public static void main(String [] args) throws ClassNotFoundException{
doSome();
}
*/
//第二种方式:
//try..catch进行捕捉
public static void main(String [] args) {
try {
doSome();
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void doSome() throws ClassNotFoundException {
System.out.println("doSome!!!");
}
}
package javaCoreTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 处理异常的第一种方式:在方法声明的位置上使用throws关键字抛出,谁调用这个方法,就抛给谁,抛给调用者来处理
*/
public class ExceptionTest05 {
//一般不建议在main方法上使用throws,因为这个异常如果真正发生了,一定会抛给JVM,JVM只有终止
//一般main方法中的异常建议使用try..catch进行捕捉。
public static void main(String [] args){
System.out.println("main begin");
try {
m1();
//若以上代码出现异常,直接进入catch语句中执行
System.out.println("hello");
}catch(IOException e) {
//e引用保存的内存地址是那个new出来异常对象的内存地址
System.out.println("文件不存在,可能路径错误");
System.out.println(e);//java.io.FileNotFoundException: D:\Users\SKX\Downloads\周测.docx (系统找不到指定的路径。)
}
//try..catch把异常抓住之后,这里的代码会继续执行
System.out.println("main over");
}
private static void m1() throws IOException{
System.out.println("m1 begin");
m2();
System.out.println("m1 over");
}
private static void m2() throws IOException {
System.out.println("m2 begin");
m3();
System.out.println("m2 over");
}
private static void m3() throws FileNotFoundException{
/*
* 编译报错的原因?
* 第一:这里调用了一个构造方法:FileInputStream(String name)
* 第二:这个构造方法的声明位置上有:throws FileNotFoundException
* 第三:通过类的继承结构看到:FileNotFoundException父类是IOException,IOException的父类是Exception,
* 最终得到,FileNotFoundException是编译时异常。
*/
new FileInputStream("D:\\Users\\SKX\\Downloads\\周测.docx");
}
}
(4)、异常对象有两个非常重要的方法:
-获取异常简单的描述信息:
String msg = exception.getMessage();
-打印异常追踪的堆栈信息:
exception.printStackTrace();
package javaCoreTest;
/*
* 异常对象有两个非常重要的方法:
-获取异常简单的描述信息:
String msg = exception.getMessage();
-打印异常追踪的堆栈信息:
exception.printStackTrace();
*/
public class ExceptionTest07 {
public static void main(String [] args) {
//这里只是new了异常对象,但是没有将异常对象抛出,JVM会认为这是一个普通的java对象
NullPointerException e = new NullPointerException("空指针异常");
String msg = e.getMessage();
System.out.println(msg);//空指针异常
//打印异常堆栈信息
//java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印
e.printStackTrace();
System.out.println("hello");
}
}
(5)、关于try…catch中的finally
-在finally子句的代码是最后执行的,并且一定会执行,即使try语句块中的代码出现了异常。
-finally子句必须和try一起出现,不能单独编写
package javaCoreTest;
//try 和 finally,没有catch可以吗?
//可以
public class ExceptionTest08 {
public static void main(String [] args) {
/*
* 以下代码的执行顺序:
* 先执行try
* 再执行finally
* 最后执行return(return语句只要执行方法必然结束)
*/
try {
System.out.println("try...");
return ;
}finally {
System.out.println("finally....");
}
}
}
package javaCoreTest;
public class ExceptionTest09 {
public static void main(String [] args) {
try {
System.out.println("try...");
//退出JVM
System.exit(0);//退出JVM之后,finally中的代码就不执行了
}finally {
System.out.println("finally....");
}
}
}
(6)、finally语句通常使用在哪些情况下?
通常在finally语句块中完成资源的释放/关闭。
因为finally中的代码比较有保障。即使try语句块中的代码出现,finally中代码也会正常执行。
package javaCoreTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 关于try..catch中的finally
*/
public class ExpectionTest07 {
public static void main(String [] args) {
FileInputStream fis = null;
try {
//创建输入流对象
fis = new FileInputStream("C:\\course\\javase");
String s= null;
//这里一定会出现空指针异常
s.toString();
//流使用完需要关闭,因为流是占用资源的
//fis.close();//放在这里如果上面的语句出现异常,就不会执行到此处
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}catch(NullPointerException e) {
e.printStackTrace();
}finally {
if(fis != null) {
try {
//close()方法有异常,采用捕捉的方式
fis.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
}
(7)、自定义异常类
在实际开发中,有很多业务,这些业务出现异常之后,JDK中都是没有的,程序员可以自定义异常。
自定义异常需要两步:
- -编写一个类继承Exception或者RuntimeException
- -提供两个构造方法,一个无参数,一个有参数
- 例:
package javaCoreTest;
//自定义异常
public class MyException extends Exception{//编译时异常
public MyException() {
}
public MyException(String s) {
super(s);
}
}
/*
* public class MyException extends RunTimeException{//运行时异常
*
* public MyException(){
*
* }
*
* public MyException(String s){
*
* super(s);
* }
* }
*/
(8)、重写之后的方法不能比重写之前的方法抛出更多的异常,可以更少。
例:
package javaCoreTest;
import java.io.IOException;
//重写之后的方法不能比重写之前的方法抛出更多的异常,可以更少。
public class ExceptionTest12 {
}
class Animal12{
public void doSome() {
}
}
class Cat12 extends Animal12{
//error
/*public void doSome throws Exception{
}*/
public void doSome() {
}
}
class Person{
public void doOther () throws Exception{
}
}
class Chinese extends Person{
//编译通过
/*public void doOther() {
}*/
//编译通过
/*public void doOther () throws IOException{
}*/
//编译通过
public void doOther() throws NullPointerException{
}
}
package javaCoreTest;
/*
* final finally finalize有什么区别?
*/
public class ExceptionTest11 {
public static void main(String [] args) {
//final是一个关键字,表示最终的,不变的。
final int i = 100;
//finally也是关键字,和try联合使用,使用在异常处理机制中
try {
}finally {
System.out.println("finally...");
}
//finalize()是Object类中的一个方法,作为方法名出现
//finalize是标识符
}
}
package javaCoreTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
//JDK8.0的新特性
public class ExceptionTest06 {
public static void main(String [] args) {
try {
//创建输入流
FileInputStream fis = new FileInputStream("C:\\curse\\02-javaSE");
//进行数学运算
System.out.println(100 / 0);
}catch(FileNotFoundException | ArithmeticException | NullPointerException e) {
System.out.println("文件不存在?数学异常?空指针异常?都有可能");//JDK8.0之后允许出现上面的写法
}
}
}
package javaCoreTest;
//java 面试题
public class ExceptionTest10 {
public static void main(String [] args) {
int result = m();
System.out.println(result);//100
}
/*
* java语法规则(有一些规则是不可能破坏的):
* -方法体中的代码必须遵循自上而下顺序依次执行(亘古不变)
* -return语句一旦执行,整个方法必须结束
*/
public static int m() {
int i = 100;
try {
return i;
}finally {
i++;
}
}
}