异常是什么?
1.异常模拟的是现实世界中的“不正常”事件
2.java中采用“类”去模拟异常
3.类是可以创建对象的
异常的作用?
程序发生异常事件后(比如空指针),为我们输出详细的信息,程序员通过这个信息,可以对程序进行一些处理,使程序更加健壮
前面的代码发生了异常并且没有处理,那么下面的代码也不会执行了,直接退出JVM
public class Test01 { public static void main(String[] args) { int m = 10 ; int n = 0 ; System.out.println(m/n); System.out.println("hello world"); //不会输出 } }
如果捕获异常后可以,比如
package exceptiontest; public class Test01 { public static void main(String[] args) { int m = 10 ; int n = 0 ; try { System.out.println(m/n); } catch (Exception e){ e.printStackTrace(); } System.out.println("hello world"); } }
java.lang.ArithmeticException: / by zero
at exceptiontest.Test01.main(Test01.java:10)
hello world
如果使用throws来抛出异常,则hello world不会输出,如
package exceptiontest; public class Test03 { public static void main(String args[] ) throws Exception{ int m = 10; int n = 0; System.out.println(m/n); System.out.println("hello world "); //不会输出 } }
异常继承结构
Throwable:所有异常都是可以抛出的
Error:java程序运行中如果出现了错误,错误是不能处理的,只能退出JVM,例如StackOverflowError。Error类描述了java运行时系统的内部错误和资源耗尽错误,这种情况很少出现。
Exception是可以处理的,如果没有处理异常,则直接退出JVM
RuntimeException:运行时异常,由程序错误导致的异常属于RuntimeException,而程序本身没问题,但由像I/O错误这类问题导致的异常属于其他异常,或者说编译时异常。可以说,如果出现RuntimeException,那么一定是你的问题,常见的有上面的ArithmeticException,NullPointerException等
编译时异常:Exception所有的直接子类都是编译时异常,如IOException
编译时异常和运行似乎异常
所有的编译时异常,要求程序员在编写程序阶段必须对它进行处理,不处理的话,编译无法通过。有两种处理方式:捕捉(try catch ) 和声明抛出(在方法声明的位置上使用throws关键字抛出异常),出现几率比较高
对于运行时异常,编写程序阶段不需要对其进行处理,出现几率比较低
关于try{}catch{}语句块
catch{.....}可以写多个,但是必须从上到下,从小(类型异常)到大(类型异常),最多只会执行1个catch{...},之后try{}catch{}语句块就结束了,然后将继续向下执行,throws可以抛出多个异常,用逗号隔开,而且没有大小顺序之分
public class Test02 { public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("D:/test.txt");//发生异常, //try{}中下面得语句将不再执行 //JVM会自动创建一个FileNotFoundException类型的对象,将该对象的内存地址赋值给catch语句块中的e变量 System.out.println("rererere");//不会输出 fis.read(); }catch (FileNotFoundException e){//e内存地址指向堆中那个对象是FileNotFoundException类型的事件 System.out.println("文件未找到"); //FileNotFoundException复写了toString方法 System.out.println(e); }catch (IOException e){ System.out.println("其他IO异常"); } System.out.println("hello world"); } }
文件未找到
java.io.FileNotFoundException: D: est.txt (系统找不到指定的文件。)
hello world
关于finally语句块
1.finally可以直接和try语句块联用,如:try{}finally{}
2.finally中的语句是一定会执行的
public class Test04 { public static void main(String[] args) { try{ System.out.println("try~"); return; }finally{ System.out.println("finally~"); } } }
输出:
try~
finally~
只有一种情况finally语句块不会执行,那就是在finally语句块之前退出了JVM,如
public class Test05 { public static void main(String[] args) { try{ System.out.println("before exit...."); System.exit(0); //退出JVM System.out.println("try....."); }finally { System.out.println("finally...."); } } }
输出:before exit....
又一个例子
public class Test06 { public static void main(String[] args) { int i = fun(); System.out.println("main..... i = " + i); } public static int fun(){ int i = 0; try{ i = 10; return i; }finally { i++; System.out.println("finally ..... i = " + i); } } }
finally ..... i = 11
main..... i = 10
上面try{}中执行原理是这样的
try{ i = 10; int tmp = i;//创建一个临时变量来保存i,并返回这个值 return tmp; }finally { i++; //这里操作的是i而不是tmp System.out.println("finally ..... i = " + i); }
final、finalize、finally的区别
这几个完全没有关系哈OTZ
1.final修饰的类无法被继承,修饰的方法无法被覆盖,修饰的局部变量一旦赋值不可再改变,修饰的成员变量需要手动赋值,另外,final和static修饰的变量称为常量
2.finalize压根就不是关键字,是Object类里的一个方法的名字,垃圾回收器在回收java对象前会自动调用java调用java对象的finalize方法
3.finally是异常机制中的finally语句块
自定义异常
1.编译时异常,直接继承Exception
2.运行时异常,直接继承RuntimeException
package exceptiontest; public class Test07 { public static void main(String[] args) { CustomerService cs = new CustomerService(); try{ cs.register("kobe"); }catch (IllegalNameException e){ System.out.println(e.getMessage()); } System.out.println("yyyyy"); } } class IllegalNameException extends Exception{ //定义异常一般提供两个构造方法,嗯 这是套路 public IllegalNameException(){ } public IllegalNameException(String msg){ super(msg); } } class CustomerService{ public void register(String username) throws IllegalNameException{//里面异常,所有需要throws抛出告诉外面 if (username.length() < 6){ //创建异常对象,手动抛出,是throw不是throws,用的地方不同啊 throw new IllegalNameException("用户名长度不能小于6"); } System.out.println("注册成功!"); } }
用户名长度不能小于6
yyyyy
重写的方法不能比被重写的方法抛出更宽泛的异常
举个栗子
class A{ public void fun(){ } } class B extends A{ @Override public void fun() throws Exception{ //子类无法抛出比父类更多的异常 super.fun(); } }
以上编译错误:
Exception Exception is not compatible with throws clause in A.fun()
再举个栗子
class A{ public void fun() throws FileNotFoundException{ } } class B extends A{ @Override public void fun() throws IOException{ //编译错误,子类无法抛出比父类更大(宽)的异常 super.fun(); } }
又一个栗子
class A{ public void fun() throws IOException{ } } class B extends A{ @Override public void fun() throws FileNotFoundException{ //编译通过 } }