您的位置:首页 > 职场人生

黑马程序员-java异常

2013-04-20 00:25 134 查看

-------
android培训、java培训、期待与您交流! ----------

java异常处理机制

java根据异常的不同,将异常分为错误和异常两种

1.错误:错误是指程序在执行过程中所遇到的硬件或操作系统的错误,如内存溢出还有虚拟机错误之类的,程序本身不能处理错误,得靠外界干预,否则无法正常运行

2.异常:是指java可以处理的错误,如数组下标越界啊,除数为0啊,java提供了强大的异常处理机制,使程序能够自动的捕获异常,并调整程序运行的方向,使程序可以继续运行

在java的异常处理机制中,有两个最常用的类,分别是Exception和Error,它们位于java.lang包中,是Throwable的子类,关系如下图



Error:指的是jvm的错误,一般在程序中无法处理

Exception:指的是程序中出现的问题,一般在代码块中加入try..catch语句进行处理,或者将它抛出交给调用者处理(抛出异常不代表程序停止 RuntimeException 及其子类除外)

RuntimeException :此异常与此异常的子类的对象在程序中被抛出后,无需对他进行捕捉,直接交给jvm处理,届时程序将停止工作。

异常这一章的几个关键字

throw:此关键字可以将一个异常对象抛出。

throws:这个关键字用在方法声明的后面,标示此方法可能会抛出异常,告诉调用者,调用者就会对这个对象进行捕捉或者继续向上抛出。
finally:此关键字用在try......catch语句之后,不管前面有没有捕捉到异常,finally后面的代码块一定会被执行,一般用在关闭数据库的各项连接上。

看下面几段代码

1.try...catch语句的使用

实例1

public class TestException {

public static void main(String[] args) {
String str1 = "8";
String str2 = "2";
TestException.getResult(str1, str2);	//调用静态方法
System.out.println("ok");

}

//定义一个静态方法,用于取得两数之商
public static int getResult(String a, String b) {
int value = 0;
/*		int num1 = Integer.parseInt(a);
int num2 = Integer.parseInt(b);
value = num1/num2;*/
try {
//将字符串转为int值
int num1 = Integer.parseInt(a);
int num2 = Integer.parseInt(b);
value = num1/num2;
System.out.println("运算结果是" + value);

} catch (ArithmeticException e) {
System.out.println(e.getMessage());

} catch (NumberFormatException e) {
//打印出错信息
System.out.println(e.getMessage());
//打印出错的类型和信息
System.out.println(e.toString());
//打印出错的栈堆信息,就是方法的层次调用
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("我一定会出现的");
}
return value;
}

}


运行总结

由这段代码可看出,因为被除数的数值是不确定的,有可能是0,也有可能说起他的数,如若在getResult方法中没有对可能出现的ArithmeticException异常进行捕捉,程序会立刻中断并报错,最后的ok将不会被打印,但如果在方法中用try...catch 语句进行捕捉,异常捕捉后打印相关的信息,最后ok还是会被打印出来的,在finally后面代码块中的语句一定会被执行,“我一定会出现这句话” 不管有没有捕捉到异常都会出现。一个方法中抛出异常并且被本方法中的 catch 语句捉住的话,处理相关完错误信息,之后程序将无法回到错误产生的下一行代码执行,只能跳到
try..catch 语句外执行,直到方法结束,然后从调用这个方法的下一行继续执行,直到程序结束,还有,在 finally 语句中如果抛出异常,这个异常无法被上面的 catch 捕捉住,只有在方法的后面用 throws 关键字声明该方法可能会抛出某个异常才行

在此需要注意以下几点

1.

try...catch语句中最后的finally代码块可写可不写,如若不写,编译不会报错,如果写了,就一定会被执行。

2.

在 catch 语句中,如果有 Exception 子类的情况下,一定要把子类异常写在上面,如若不然,所有异常都会被Exception捉住,后面的catch语句就相当于废话了。

3.

如果在getResult方法中没有对异常进行捕捉,而是对他进行抛出,交给调用者处理,这样也是可以的,后面的代码将对此进行体现。

在Throwable类中封装了几个常用的方法,常用的有toString(),将打印错误的类型和信息,toMessage()打印的是出错的信息,而printStackTrace()将会打印出错的栈堆信息(方法的层次调用)。

2.自定义异常类

在java中,一切皆是对象,所谓的异常也就是一个用异常类创建出来的对象,java提供了非常多的异常对象,同时java也允许程序员创建属于自己的异常类,如果想自己定义一个异常的类,

一般是使这个类继承Exception(当然继承RuntimeException也是可行的)

看下面一段代码

实例2

public class TestMyException {

public static void main(String[] args) {
try {
TestMyException.getResult(8, -2);
} catch (MyException e) {
System.out.println(e.toString());
}

}

public static int getResult(int a, int b) throws MyException {
if(a <= 0 || b <= 0) {
throw new MyException("输入的数据不符合规则");
} else {
return a*b;
}
//return a*b;
}

}

class MyException extends Exception {

public String toString() {
return super.toString();
}

//String message = "信息错误";
MyException(String message) {
//调用父类构造方法
super(message);
}

}


这段代码自定义异常是继承Exception类的,继承了 Exception 的异常在某一方法中被抛出后,方法后必须更上throws 自定义异常类名,否则编译无法通过,与此相对的如果继承 RuntimeException就不需要进行throws声明,在调用者中也不需要用try...catch语句进行捕捉,直接交给jvm进行处理即可,jvm调用e.printStackTrace()后程序将停止.并不是说一旦抛出 RuntimeException 及其子类的异常对象程序就会停止,你如果像 Exception 一样捕捉他们的话,程序还是会继续运行的.

3.关于标示异常方法的重写

实例3

/*
该程序用于测试如何重写抛出异常的方法
*/
public class TestMyException {

public static void main(String[] args) {

try {
System.out.println(new Rectangle(5,-8).getArea());
} catch (MyException2 e) {
System.out.println(e.toString());
}

}

}
//自定义一个异常
class MyException extends Exception {

MyException(String message) {
super(message);
}

}

//自定义另一个异常,继承上一个异常
class MyException2 extends MyException {

String message;

MyException2(String message) {
//调用父类构造方法
super(message);
this.message = message;
}

public String toString() {
return message;
}
}

//定义一个几何图形抽象类,
abstract class Shape {
//声明一个计算面积的抽象方法
public abstract int getArea() throws MyException2;
}

//定义一个矩形类
class Rectangle extends Shape {

private int len, width;

public Rectangle(int len,int width) {
this.len = len;
this.width = width;
}
//重写父类的抽象方法
//注意:覆写父类的方法时只能抛出父类的异常以及父类异常的子类,不能抛出比父类异常还大的异常,如果父类方法没有抛出异常,子类也不能抛,只能用try catch语句捉住
public int getA
4000
rea() throws MyException2 {

if(len <= 0 | width <= 0) {
throw new MyException2("输入的数据错误");
} else {
return len*width;
}
}
}


4.使用 finally 关键字应该注意的地方,众说周知,finally 中的语句总是能得到执行,这时候应该注意一个问题,就是try语句的嵌套,很可能会套出问题来,致使你的异常对象被吞了

实例4

import java.io.FileNotFoundException;
import java.io.IOException;

public class TestFinally {

public static void main(String[] args) {
TestFinally.runTest();
}

public static void runTest() throws RuntimeException {
try {
try {
throw new RuntimeException("asdasd");
} finally {
throw new NullPointerException("sdfsadfasdfasdf");
}
} catch(RuntimeException e) {
System.out.println(e.toString());
}
}
}


这个后面的异常对象明显将前面的覆盖了,前面的异常对象被吞了

多线程与 RuntimeException 

抛出 RuntimeException ,不捕获的话,主线程将停止,当前程序将关闭,这是单线程,如果是多线程的话,有一条线程抛出了 RuntimeException 异常,是整个程序停止,还是那个线程停止

让我们来试试

实例4

public class TestThreadException {

public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {

public void run() {
while(true) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}

}, "线程1");
Thread t2 = new Thread(new Runnable() {
int i = 1;
public void run() {
while(true) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i == 150) {
//try {
throw new RuntimeException();
/*						} catch(RuntimeException e) {

}*/
}
System.out.println(Thread.currentThread().getName() + "----" + i);
i++;
}
}

}, "线程2");
t1.start();
t2.start();
}
}


这个程序很有意思,线程2如果执行到到第150次循环会抛出一个 RuntimeException 异常,该线程停止,但是程序还没有停止,线程1还在循环执行,说明一个程序如果抛出 RuntimeException异常,程序不一定会停止,只是抛出异常的线程会停止,这个一定要注意.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java