1.异常:程序运行时发生了不期望的事,它阻止了程序按按程序员的预期正常执行。
2.异常的意义:
Java的" 异常机制"就是在处理各类问题时给了程序员非常简单而灵活的方式。一般来说,其它高级语言主要是让函数使用者来关注该函数可能会出现的异常情况,而 java则是把这件事情交给方法的设计者来做。这对于方法的使用者来说带来的方便是不会因为责任心不强,或者办事丢三那四,会忘了在使用方法时处理可能发生的异常情况。
3.异常类:
>错误(Error):程序无法处理的错误。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。
>异常(Exception):程序运行中可以处理的错误。Exception又分为运行时异常(RuntimeException)和非运行时异常。
4.运行时异常(RuntimeException)和非运行时异常。
>运行时异常(RuntimeException):程序运行中可以捕获处理,也可不处理一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。主要有:
NullPointerException(空指针异常)
ClassCastException(类型强制转换异常)
ArithmeticExecption(算术异常类)
IllegalArgumentException(传递非法参数异常)
ArrayStoreException(向数组中存放与声明类型不兼容对象异常)
IndexOutOfBoundsException (下标越界异常)
NegativeArraySizeException (创建一个大小为负数的数组错误异常)
NumberFormatException (数字格式异常)
SecurityException (安全异常)
UnsupportedOperationException (不支持的操作异常)
>非运行时异常:必须处理异常,如果不处理,编译不能通过。
IOException(文件读写异常)
FileNoteFoundException(文件未找到异常)
EOFException(读写文件尾异常)
MalfformedURException(URL格式错误异常)
SockeyException(Socket异常)
SQLException(SQL数据库异常)
5.异常参数:与java其他对象一样,我们总使用new在堆上创建异常对象,这也伴随着存储空间的分配和构造器的调用。所有标准类有两个构造器:一个是默认构造器(throw new Exception()),另一个是接受字符串作为参数(throw new Exception(“t==null”))。
6.处理异常机制:抛出异常好捕捉异常
>抛出异常:一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。
>捕捉异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
补充:异常总是先被抛出,后被捕捉。
7.捕捉异常:try,catch,finally
>try-catch:
try {
// 可能会发生异常的程序代码
} catch (Type1 id1){
// 捕获并处置try抛出的异常类型Type1
}
catch (Type2 id2){
//捕获并处置try抛出的异常类型Type2
}
例如:
public static void main(String[] args) {
int a[]=new int[3];
try { int i=0;
for(;i<=a.length;i++) {
a[i]=i;
System.out.println("a["+i+"]="+a[i]);
}
}catch(Exception e) {
System.out.println("数组下标越界异常:");
}
}
>try-catch-finally:finally子句。它表示无论是否出现异常,都应当执行的内容
try {
// 可能会发生异常的程序代码
} catch (Type1 id1) {
// 捕获并处理try抛出的异常类型Type1
} catch (Type2 id2) {
// 捕获并处理try抛出的异常类型Type2
} finally {
// 无论是否发生异常,都将执行的语句块
}
例如:
public static void main(String[] args) {
String a[]= {"Holle word!","Holle word!!","Holle word!!!"};
try {
int i=0;
while(i<4) {
System.out.println(a[i++]);
}
}catch(Exception e) {
System.out.println("数组下标越界");
}finally {
System.out.println("正常运行:");
}
}
>try-catch-finally规则:
1) 必须在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。
2) 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。
3) catch 块与相应的异常类的类型相关。
4) 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,
如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块,不会再执行其他的 catch代码块
>try-catch-finally执行顺序:
1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;
2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,
finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;
3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,
程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,
catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;
补充:
try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。
如果try块中有return语句时,finally将在返回之前被执行。
8.抛出异常;
>throw:用于方法体内部,用来抛出一个Throwable类型异常。
>throws:用于方法体外部的方法声明部分,用来声明方法可能会抛出某些异常。仅抛出了异常,该方法的调用者才能必须处理或者重新抛出异常
public class ThrowsException {
public static void pop() throws Exception {
int a[]=new int [-3];
}
public static void main(String[] args) {
try{
ThrowsException.pop();
}catch(Exception e) {
System.out.println("数组下标异常:");
}
}
}
9.自定义异常:自己来定义异常来表示程序中可能遇到的特定的问题。
class SimpleException extends Exception{}
public class MySelfException {
public static void f() throws SimpleException{
System.out.println("The SimpleException from f()");
throw new SimpleException();
}
public static void main(String[] args) {
try{MySelfException.f();
}catch(SimpleException s) {
System.out.println("catch it!");
}
}
}
上述代码中SimpleException是自定义异常,所有自定义异常都继承于Exception。10.异常类的主要方法:
方法有:
public String getMessage():返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。
public Throwable getCause():返回一个Throwable 对象代表异常原因。
public String toString():使用getMessage()的结果返回类的串级名字。
public String getLocalizeMessage():获取本地化的出错信息。
public void printStackTrace():打印toString()结果和栈层次到System.err,即错误输出流
public Throwable fillInStackTrace():用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中
程序代码实现: public static void main(String[] args) {
int a=5;
int b=0;
try {
System.out.println(a/b);
throw new Exception();
}catch( Exception e) {
System.out.println("getMessage()"+e.getMessage());//返回关于发生的异常的详细信息
System.out.println("getCause()"+e.getCause()); //返回一个Throwable 对象代表异常原因
System.out.println("toString()"+e.toString()); //使用getMessage()的结果返回类的串级名字。
e.printStackTrace(System.out); //打印toString()结果和栈层次到System.err,即错误输出流
System.out.println("toString()"+e.fillInStackTrace()); //用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。
}
}
运行结果:
getMessage()/ by zero
getCause()null
toString()java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
at TeseException.ExceptionMethods.main(ExceptionMethods.java:9)
toString()java.lang.ArithmeticException: / by zero
11.栈轨迹:
>printStackTrace()方法所提供的信息可以通过getStrackTrace()方法来直接访问,这个方法将返回一个由栈轨迹中的元素所构成的数组,其中每一个元素都表示栈中的一帧。元素0是栈顶元素,并且是调用序列中的最后一个元素和栈底是调用序列中的第一个方法调用。
实现代码为:
public class TestStackTrace {
static void f() {
try {
throw new Exception();
}catch(Exception e) {
for(StackTraceElement st:e.getStackTrace()) {
System.out.println(st.getMethodName());
}
}
}
static void g() {
f();
}
static void h() {
g();
}
public static void main(String[] args) {
f();
g();
h();
}
}
运行结果为:
f
main
f
g
main
f
g
h
main