1.异常的基本概念
(1)异常是什么?
第一,异常模拟的是现实世界中“不正常“的事件。
第二,java中采用“类”去模拟异常。
第三,类是可以创建对象的。
NullpointerException e=0x1234;
e是引用类型,e中保存的内存地址指向堆中的“对象”,这个对象一定是NullpointerException 类型。这个对象就表示真实存在的异常事件。NullpointerException 是一类异常。
(2)异常机制的作用是什么?
java语言为我们提供了一种完善的异常处理机制。
作用是:程序发生异常事件之后,为我们输出详细的错误信息。程序员通过这个信息,可以对程序进行一些处理,使程序更加健壮。
2.异常类继承层次结构
Error:java程序中如果出现了错误,错误是不能处理的,只能退出JVM。例如:StackOverflowError。可抛出,不可处理。
Exception:可抛出,也可处理。如果没有处理异常,则程序直接退出JVM。
异常继承结构图如下所示:
3.两种处理异常方式
处理异常有两种方式:
(1)声明抛出 throws
下面是第一种方式 声明抛出
第一个例子
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Testhrows {
public static void main(String[] args) throws FileNotFoundException {
//创建文件输入流,读取文件
//java编辑器不是那么智能,因为FileInputStream这个构造方法在声明的位置上使用了throws FileNotFoundException
FileInputStream file=new FileInputStream("c:/ab.txt");
}
}
下面是第二个例子:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class TestThrows02 {
public static void main(String[] args) throws FileNotFoundException {
m1();
//使用throws处理异常不是真正处理异常而是推卸责任
//谁调用的就会抛给谁
//上面的m1方法如果出现了异常,因为采用的是上抛,给了JVM,JVM遇到这个异常就会推出JVM,下面的代码不会执行
//System.out.println();
//真正处理
try{
m1();
}
catch(FileNotFoundException e){}
System.out.println();
}
public static void m1() throws FileNotFoundException{
m2();
}
public static void m2() throws FileNotFoundException{
m3();
}
public static void m3() throws FileNotFoundException{
new FileInputStream("c:/cd.txt");//FileInputStream构造方法声明位置上使用throws(向上抛)
}
}
(2)捕捉 try…catch…
语法:
try{
可能出现异常的代码;
}catch{
处理异常的代码;
}catch{
处理异常的代码;
}…….
第一,catch语句块可以写多个。
第二,但是从上到下catch,必须从小类型异常到大类型异常进行捕捉。
第三,try catch中最多执行一个catch语句块,执行结束后,try catch结束。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestTryCatch {
/*
* 下面编译无法通过,catch可以写多个,但是必须从上到下,从小到大捕捉。
*/
/*public static void main(String[] args) {
try {
FileInputStream file=new FileInputStream("c:/cd.txt");
file.read();
}catch (IOException e) {
}catch (FileNotFoundException e) {
}
}*/
//通过
/*public static void main(String[] args) throws FileNotFoundException,IOException {
FileInputStream file=new FileInputStream("abc");
file.read();
}*/
public static void main(String[] args) {
try {
//程序执行到此处发生了FileNotFoundException类型的异常。
//JVM会自动创建一个FileNotFoundException类型的对象,将该对象的内存地址赋值给catch语句块中的e变量。
FileInputStream file=new FileInputStream("abc");
//上面的代码出了异常try语句块中的代码不再执行,直接进入catch语句块中执行。
System.out.println("111111111111");
file.read();
System.out.println("222222222222");
}catch (FileNotFoundException e) {//e内存地址指向堆中的那个对象是“FileNotFoundException”类型的事件。
System.out.println("读取文件不存在");//java.io.FileNotFoundException: abc (系统找不到指定的文件。)
System.out.println(e);
}
catch (IOException e) {
System.out.println("其他异常");
}
System.out.println("hello world");
}
}
输出结果:
读取文件不存在
java.io.FileNotFoundException: abc (系统找不到指定的文件。)
hello world
4.getMessage和printstackTrace方法的应用
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class TestTryCatch05 {
public static void main(String[] args) {
try {
FileInputStream file=new FileInputStream("c:/kkjgd.txt");
//JVM为我们执行了以下代码
//FileNotFoundException e=new FileNotFoundException("c:/\\kkjgd.txt (系统找不到指定的文件。)");
} catch (FileNotFoundException e) {
//打印异常堆栈信息。一般情况下,都会使用该方式去调试程序。
e.printStackTrace();
/*java.io.FileNotFoundException: c:\kkjgd.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at TestTryCatch05.main(TestTryCatch05.java:8)*/
System.out.println(e.getMessage());//c:\kkjgd.txt (系统找不到指定的文件。)
}
System.out.println("abcdef");
}
}
5.finally语句
第一,finally语句块可直接和try语句块联用。try…finally
第二,try…catch…finally
第三,在finally语句块中的代码一定会执行的。所以通常为了保证某资源一定会释放,所以一般在finally语句块中释放资源。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class TestFinally {
public static void main(String[] args) throws Exception {
try {
//会执行
System.out.println("try");
return;
} finally {
//会执行
System.out.println("finally");
}
try {
FileInputStream file=new FileInputStream("ddet.txt");
//不会执行
System.out.println("try");
} finally {
//会执行
System.out.println("finally");
}
try {
//只要在执行finally语句块之前推出了JVM,则finally语句块不会执行
System.exit(0);
} finally {
//不会执行
System.out.println("finally");
}
}
}
深入finally:
public class Testfinally02 {
public static void main(String[] args) {
int i=m1();
System.out.println("main的i是"+i);//10
}
public static int m1(){
int i=10;
try {
//底层其实是这样操作的
//int tmp=i;return tmp;
return i;
} finally {
i++;
System.out.println("m1的i是"+i);
}
}
}
输出结果
m1的i是11
main的i是10
释放资源例子
import java.io.File;
import java.io.FileInputStream;
public class Testfinally04 {
public static void main(String[] args) {
FileInputStream file=null;
try {
file=new FileInputStream("Test.java");
} catch (Exception e) {
e.printStackTrace();
}finally {
//为了保证资源一定会释放
if(file!=null){
try {
System.out.println("finally try");
file.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
}
6.final finalize(方法名,垃圾回收器回收对象前调用) finally
7.如何手动抛出异常
(1)自定义异常
编译时异常:直接继承Exception
运行时异常:直接继承RuntimeException
public class MyException extends Exception{//编译时异常
//public class MyException extends RuntimeException{//运行时异常
//定义异常一般提供两个构造方法
public MyException(){}
public MyException(String msg){
super(msg);
}
}
public class CustomService {
//对外提供一个注册的方法
public void register(String name) throws MyException{
if(name.length()<6){
//异常
//创建异常对象
//MyException e=new MyException("用户名长度不能少于六位");
//手动抛出异常
//throw e;
throw new MyException("用户名长度不能少于六位");
}
//如果代码能执行到此处,证明用户名是合法的
System.out.println("注册成功");
}
}
public class TestException {
public static void main(String[] args) {
//假如用户提供用户名如下
String username="jack";
CustomService cs=new CustomService();
try {
cs.register(username);
} catch (MyException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
;
}
}
输出结果:
用户名长度不能少于六位
MyException: 用户名长度不能少于六位
at CustomService.register(CustomService.java:11)
at TestException.main(TestException.java:9)
8.方法的覆盖与异常
重写的方法不能比被重写的方法抛出更宽泛的异常。
//下例,不能通过编译。
import java.io.FileNotFoundException;
import java.io.IOException;
public class A {
public void m1() throws FileNotFoundException {
}
}
class B extends A{
//子类永远无法抛出比父类更多的异常
public void m1() throws IOException{}
}
//可以通过编译
import java.io.FileNotFoundException;
import java.io.IOException;
public class A {
public void m1() throws IOException {
}
}
class B extends A{
public void m1() throws FileNotFoundException{}
}