异常 认识异常 1、什么是异常,java提供异常处理机制有什么用? 以下程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常 java语言是很完善的语言,提供了异常的处理方式,以下程序执行过程中出现了不正常情况, java把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对 程序进行修改,让程序更加的健壮。
什么是异常:程序执行过程中的不正常情况。 异常的作用:增强程序的健壮性。
2、以下程序执行控制台出现了: Exception in thread “main” java.lang.ArithmeticException: / by zero at com.bjpowernode.javase.exception.ExceptionTest01.main(ExceptionTest01.java:14) 这个信息被我们称为:异常信息。这个信息是JVM打印的。
3、重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class ExceptionTest01 { public static void main (String[] args) { int a = 10 ; int b = 0 ; int c = a / b; System.out.println(a + "/" + b + "=" + c); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.bjpowernode.javase.exception;public class ExceptionTest02 { public static void main (String[] args) { NumberFormatException nfe = new NumberFormatException ("数字格式化异常!" ); System.out.println(nfe); NullPointerException npe = new NullPointerException ("空指针异常发生了!" ); System.out.println(npe); } }
异常处理机制 1、异常在java中以类和对象的形式存在。那么异常的继承结构是怎样的? 我们可以使用UML图来描述一下继承结构。 画UML图有很多工具,例如:Rational Rose(收费的)、starUML等…. Object Object下有Throwable(可抛出的) Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的) Exception下有两个分支: Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常。)。 RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不管,都行。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class ExceptionTest04 { public static void main (String[] args) { } public static void doSome () throws ClassNotFoundException{ System.out.println("doSome!!!!" ); } }
2、编译时异常和运行时异常,都是发生在运行阶段。编译阶段异常是不会发生的。 编译时异常因为什么而得名? 因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。 所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象。 因为异常的发生就是new异常对象。
3、编译时异常和运行时异常的区别?
编译时异常一般发生的概率比较高。 举个例子: 你看到外面下雨了,倾盆大雨的。 你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。 而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。 “拿一把伞”就是对“生病异常”发生之前的一种处理方式。
对于一些发生概率较高的异常,需要在运行之前对其进行预处理。
运行时异常一般发生的概率比较低。 举个例子: 小明走在大街上,可能会被天上的飞机轮子砸到。 被飞机轮子砸到也算一种异常。 但是这种异常发生概率较低。 在出门之前你没必要提前对这种发生概率较低的异常进行预处理。 如果你预处理这种异常,你将活的很累。 假设你在出门之前,你把能够发生的异常都预先处理,你这个人会更加的安全,但是你这个人活的很累。
假设java中没有对异常进行划分,没有分为:编译时异常和运行时异常, 所有的异常都需要在编写程序阶段对其进行预处理,将是怎样的效果呢? 首先,如果这样的话,程序肯定是绝对的安全的。 但是程序员编写程序太累,代码到处都是处理异常的代码。
4、编译时异常还有其他名字: 受检异常:CheckedException 受控异常
5、运行时异常还有其它名字: 未受检异常:UnCheckedException 非受控异常
6、再次强调:所有异常都是发生在运行阶段的。
7、Java语言中对异常的处理包括两种方式:
第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。 谁调用我,我就抛给谁。抛给上一级。
第二种方式:使用try..catch语句进行异常的捕捉。 这件事发生了,谁也不知道,因为我给抓住了。
举个例子: 我是某集团的一个销售员,因为我的失误,导致公司损失了1000元, “损失1000元”这可以看做是一个异常发生了。我有两种处理方式, 第一种方式:我把这件事告诉我的领导【异常上抛】 第二种方式:我自己掏腰包把这个钱补上。【异常的捕捉】
张三 –> 李四 —> 王五 –> CEO
思考: 异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。
8、注意:Java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续 向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止java程序的执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;public class ExceptionTest06 { public static void main (String[] args) { System.out.println("main begin" ); try { m1(); System.out.println("hello world!" ); } catch (FileNotFoundException e){ System.out.println("文件不存在,可能路径错误,也可能该文件被删除了!" ); System.out.println(e); } System.out.println("main over" ); } private static void m1 () throws FileNotFoundException { System.out.println("m1 begin" ); m2(); System.out.println("m1 over" ); } private static void m2 () throws FileNotFoundException { System.out.println("m2 begin" ); m3(); System.out.println("m2 over" ); } private static void m3 () throws FileNotFoundException { new FileInputStream ("D:\\course\\01-课\\学习方法.txt" ); System.out.println("如果以上代码出异常,这里会执行吗??????????????????不会!!!" ); } }
深入理解try…catch… 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 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:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf" ); System.out.println(100 / 0 ); } catch (FileNotFoundException | ArithmeticException | NullPointerException e) { System.out.println("文件不存在?数学异常?空指针异常?都有可能!" ); } } }
异常对象的常用方法 异常对象有两个非常重要的方法:
获取异常简单的描述信息: String msg = exception.getMessage();
打印异常追踪的堆栈信息:(更常用) exception.printStackTrace();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import java.io.FileInputStream;import java.io.FileNotFoundException;public class ExceptionTest09 { public static void main (String[] args) { try { m1(); } catch (FileNotFoundException e) { String msg = e.getMessage(); System.out.println(msg); } System.out.println("Hello World!" ); } private static void m1 () throws FileNotFoundException { m2(); } private static void m2 () throws FileNotFoundException { m3(); } private static void m3 () throws FileNotFoundException { new FileInputStream ("C:\\jetns-agent.jar" ); } }
finally语句的使用 关于try..catch中的finally子句: 1、在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。 finally子句必须和try一起出现,不能单独编写。
2、finally语句通常使用在哪些情况下呢? 通常在finally语句块中完成资源的释放/关闭。 因为finally中的代码比较有保障。 即使try语句块中的代码出现异常,finally中代码也会正常执行。
3、try和finally,没有catch可以吗?可以。 try不能单独使用。 try finally可以联合使用。 以下代码的执行顺序: 先执行try… 再执行finally… 最后执行 return (return语句只要执行方法必然结束。)
4、退出JVM之后,finally语句中的代码就不执行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 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:\\course\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf" ); String s = null ; s.toString(); System.out.println("hello world!" ); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); } finally { System.out.println("hello 浩克!" ); if (fis != null ) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } System.out.println("hello kitty!" ); } }
一道finally面试题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class ExceptionTest13 { public static void main (String[] args) { int result = m(); System.out.println(result); } public static int m () { int i = 100 ; try { return i; } finally { i++; } } }
final finally finalize有什么区别?
final 关键字 final修饰的类无法继承 final修饰的方法无法覆盖 final修饰的变量不能重新赋值。
finally 关键字 和try一起联合使用。 finally语句块中的代码是必须执行的。
finalize 标识符 是一个Object类中的方法名。 这个方法是由垃圾回收器GC负责调用的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class ExceptionTest14 { public static void main (String[] args) { final int i = 100 ; try { } finally { System.out.println("finally...." ); } Object obj; } }final class A { public static final double MATH_PI = 3.1415926 ; }class B { public final void doSome () { } }
自定义异常 1、SUN提供的JDK内置的异常肯定是不够的用的。在实际的开发中,有很多业务, 这些业务出现异常之后,JDK中都是没有的。和业务挂钩的。那么异常类我们 程序员可以自己定义吗? 可以。
2、Java中怎么自定义异常呢? 两步: 第一步:编写一个类继承Exception或者RuntimeException. 第二步:提供两个构造方法,一个无参数的,一个带有String参数的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class MyException extends Exception { public MyException () { } public MyException (String s) { super (s); } }
异常在实际开发中的作用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 public class MyStack { private Object[] elements; private int index; public MyStack () { this .elements = new Object [10 ]; this .index = -1 ; } public void push (Object obj) throws MyStackOperationException { if (index >= elements.length - 1 ){ throw new MyStackOperationException ("压栈失败,栈已满!" ); } index++; elements[index] = obj; System.out.println("压栈" + obj + "元素成功,栈帧指向" + index); } public void pop () throws MyStackOperationException { if (index < 0 ){ throw new MyStackOperationException ("弹栈失败,栈已空!" ); } System.out.print("弹栈" + elements[index] + "元素成功," ); index--; System.out.println("栈帧指向" + index); } public Object[] getElements() { return elements; } public void setElements (Object[] elements) { this .elements = elements; } public int getIndex () { return index; } public void setIndex (int index) { this .index = index; } }class MyStackOperationException extends Exception { public MyStackOperationException () { } public MyStackOperationException (String s) { super (s); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 测试改良之后的MyStackpublic class ExceptionTest16 { public static void main (String[] args) { MyStack stack = new MyStack (); try { stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); stack.push(new Object ()); } catch (MyStackOperationException e) { System.out.println(e.getMessage()); } try { stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); stack.pop(); } catch (MyStackOperationException e) { System.out.println(e.getMessage()); } } }