黑马程序员_Java基础_异常

一,异常的概念:

在没有学习异常之前,我们所有的程序都是默认在理想状态下运行的,在实际开发中可能存在各种各样的问题,比如用户输入的数值不正确,,格式不正确,都会引起程序运行的错误。所谓的异常就是程序运行时出现的不正常的情况。异常也是现实生活中一个个具体的事物,java中的异常时通过java类的形式进行描述,并且封装成对象的。异常对象都是派生于Throwable类的一个实例。

二,java中的异常的体系结构:

Throwable

|——Error

|——Exception

|——RuntimeException

|——IOException

Error是严重异常,是JVM处理不了的异常,所以用户也处理不了,所以我们不需要去管。当然这种严重异常出错的概率也是比较小的。我们重点讨论的是Exception,需要我们程序员去处理的东西。

 

1RuntimeException

Exception的一个特殊子类异常RuntimeException(运行时异常),该异常在函数

部通过throw关键字抛出后可以不用再函数上声明,编译一样会通过,如果在函数上声明,调用者不用进行处理,也会通过;(面试常考)

 

2,体系中的省略号是指继承Exception,就是Exception的除RuntimeException的子类。继承Exception的子类,在函数内部抛出异常对象如果不在函数上声明,则编译不能通过,声明之后调用者不进行处理,编译也不能通过;

之所以不在函数上声明是因为不希望调用者处理,当该异常发生时,希望程序停止,因为在运行时出现了无法继续运行的情况,这时就需要停止程序对代码进行修改;

 

3,异常体系的特点:异常体系中所有类以及建立的对象都具有可抛性。

也就是说可以被throwthrows关键字操作;只有异常体系具备这个特点;

 

throwthrows的用法:

throw定义在函数内部,用于抛出异常对象;

throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开;

 

当内容有throw抛出的异常对象,并未进行try处理必须要在函数上用throws关键字抛出(声明),否则编译失败;

注意:函数内如果抛出的是RuntimeException,函数上可以不用声明。

 

三,异常的处理:

1,如果在函数上面进行声明过的异常,也就是用关键字throws在函数上面声明的异常,当在某个方法中调用这样的方法的时候,要么执行try...catch处理,要么向上一级抛出去,也就是在这个函数上面继续throws。这一点我们在使用java文档的时候可能会看到很多。当然不是所有的异常都可以进行throws的,将会在后面的笔记中总结到。

2,异常的分类:有两种:

1),编译时被检测异常;

该异常在编译时如果没有处理(没有抛,也没有try)则编译失败。

该异常被标示,代表可以被处理;

2),运行时异常,编译时不检测;

编译时不需要处理,编译不检查;

该异常发生时,建议不要处理,让程序停止,需要对代码进行修正;

 

3,异常处理的语句:

try{

 

需要被检测的代码;

 

}catch(){

 

处理异常的代码;

}finally{

 

一定会执行的代码;

 

}

 

三种形式:

1,形式一:

try{

 

}catch(){

 

}finally{

 

}

 

2,形式二

try{

 

}catch(){

 

}

 

3,形式三

try{

 

}finally{

 

}

 

Finally特点:

1,fianlly里面通常定义的是关闭资源的代码,因为资源必须释放;

2),finally只有一种情况下不会执行,当执行到System.exit(0)时,JVM结束,finally不会执行;

 

四,自定义异常方法:

1,自定义异常:是按照java的面型对象思想,将程序的特有问题进行封装;

 

在自定义异常中可以有两种选择,要么继承Exception要么继承RuntimeException

本程序重点讲解这两种用户自定义异常父类的不同。

 

1,为了让该自定义类具有可抛性;

2),让该类具备操作异类的共性方法;

 

当要定义自定义异常信息的时候,可以使用父类已经定义好的功能。异常信息传递给父类的构造函数;(多查看java文档)

 

class MyException extends Exception

{

MyException(String message) {

super(message);

}

}

 

示例一:编写一个程序,计算一个数除以另外一个数,在相除的时候,除数可能为零。定义一个负数异常继承Exception,当除数为0的时候,抛出异常,打印在控制台,并且终止整个程序,下面的程序不在执行。


class FushuException extends Exception {
	/*
	 * private String msg; FushuException(String msg) { this.msg = msg; }
	 * 
	 * public String getMessage() { return msg; }
	 */

	private int value;

	FushuException(String msg, int value) {
		super(msg);
		this.value = value;
	}

	public int getValue() {
		return value;
	}
}

class Demon5 {

	public int account(int a, int b) throws FushuException {
		if (b < 0)
			throw new FushuException("出现了负数的情况;", b);// 手动通过关键字自定义一个负数异常;
		int c = a / b;
		return c;
	}
}

class ExceptionTest {
	public static void main(String[] args) {
		Demon5 d = new Demon5();
		try {
			System.out.println(d.account(4, -5));
		} catch (FushuException e) {
			System.out.println(e.toString());
			// System.out.println("除数不能为负数!");
			System.out.println("错误的负数是" + e.getValue());
		}
	}
}

示例二:将示例一的程序进行简化,可以直接将负数异常通过throw关键字在函数内部抛出,这时候就不需要在函数上面通过throws抛给上一级。下面的程序负数异常时继承自RuntimeException,当然也可以不用定义,直接throw new RuntimeException( 异常提示 );


class Test3 {
	int div(int a, int b) {
		if (b < 0)
			throw new FushuException2("除数为负数了;");// 该异常发生后计算无法继续,希望程序停止,不需要在
			// 函数上声明;
			// 可以不用定义FushuException2,直接throw new RuntimeException("除数为零");
		return a / b;
	}
}

class ExceptionDemon {
	public static void main(String[] args) {
		Test6 t6 = new Test6();
		int c = t6.div(5, -8);
		System.out.println(c);
	}
}

示例三:自定义继承自ExceptionRuntimeException的综合例子。

需求:老师用电脑上课;(面向对象思想:名词提炼法)

老师类,电脑类

 

可能出现的异常:

电脑蓝屏;--->可以解决,重启电脑,继续上课;

电脑冒烟;--->老师不能解决,该异常跟老师没关系,如果继续往外抛,别的老师也解决不了,此时抛出老师自己的异常,不能上课了;当校长接收到这一异常时可以解决,就是放假休息的,等待电脑修好了继续上课;


class LanpingException extends Exception {
	LanpingException(String msg) {
		super(msg);
	}
}

class MaoyanException extends RuntimeException {
	MaoyanException(String msg) {
		super(msg);
	}
}

class NoplanException extends Exception {
	NoplanException(String msg) {
		super(msg);
	}
}

class Computer {
	private int state = 3;

	public void run() throws LanpingException, MaoyanException {
		if (state == 1)
			System.out.println("电脑运行。。。");
		else if (state == 2)
			throw new LanpingException("电脑蓝屏了。。。请重启");
		else if (state == 3)
			throw new MaoyanException("电脑冒烟。。。");

	}

	public void reset() {
		System.out.println("电脑重启。。。");
	}
}

class Teacher {
	private Computer cmpt;
	private String name;

	Teacher(String name) {
		this.name = name;
		cmpt = new Computer();
	}

	public void teach() throws NoplanException {
		try {
			cmpt.run();
		} catch (LanpingException e) {
			cmpt.reset();
		} catch (MaoyanException e) {
			test();
			System.out.println(e.toString());
			throw new NoplanException("无法继续上课。。。");
		}
		System.out.println(name + "老师讲课。。。");
	}

	public void test() {
		System.out.println("学生做练习。。。");
	}
}

class ExceptionExercise {
	public static void main(String[] args) {
		Teacher t = new Teacher("李");
		try {
			t.teach();
		} catch (NoplanException e) {
			System.out.println("全体放假。。。");
		}
	}
}

总结:前面已经给出了异常处理的几种代码的形式,其中finally也是十分重要的一个知识点。finally语句里面的内容无论什么情况都会执行;它的应用主要是在数据库上;因为数据库的连接资源是有限的,当发生异常时如果程序停止的话,数据库的连接如果没有断开,将会占用很多资源,这是finally语句就起到很大的作用。


public void method() throws SQLException {
	连接数据库;
	数据库的操作;
	关闭数据库;//该动作无论数据库的操作是否成功,都必须进行;
 
 
	try{
		连接数据库;
		数据库的操作;//throw new SQLException();
	}catch(SQLException e) {
		...
	}finally {
		关闭数据库;
	}
}
try...catch的另外几种格式:
	try{
		...
	}catch(Exception e) {
		...
	}
	 
	 
	try{
		...
	}catch(Exception e) {
		...
	}finally {
		...
	}
	 
	 
	try{
		...
	}finally {  //finally用于关闭资源
		...
	}//记住catch是用于处理异常,如果没有catch说明此异常没有被处理过,此时就必须声明出去;

五,子类覆盖父类时异常的处理规则:

1,子类在覆盖父类时如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。

2,如果在父类方法中抛出多个异常,子类再覆盖时只能抛出父类异常的子异常,或者不抛。例如:父类方法有A,B,C,D,E这几个异常,子类再覆盖该方法时只能抛出这五个异常的子集或者不抛。

3,如果父类或接口的方法中没有抛出异常,那么子类在覆盖该方法时也不可以抛出异常。如果子类方法发生了异常就必须用try语句解决,绝对不能向外抛。


示例分析:
class AException extends Exception {
	...
}
 
class BException extends AException {
	...
}
 
class CException extends Exception{
	...
}
 
class Fu {
	public void show() throws AException {
		...
	}
}

class Zi extends Fu
 {
	public void show() throws AException {//或者抛出BException,但是绝对不能抛CException,如果发生
	//CException那么就必须在该方法中用try语句处理掉这个异常;
		...
	}
 }
 
public class ExceptionTestDemon2 {
	public static void main(String[] args) {
		...
	}
}

六,最后给出异常的综合应用的一个例子来说明异常的应用:

需求:计算一个园和长方形的面积;对于非法值得输入可以视为获取面积出现的问题;问题可以用异常来表示。


//首先自定义一个异常
class FushuException extends RuntimeException {
	FushuException(String message) {
		super(message);
	}
}
//定义一个抽象类,将打印面积的方法放在抽象类中,子类必须重写该方法
abstract class Area {
	public abstract void getArea();
}

//计算矩形面积
class Rect extends Area {
	private double width, high;

	Rect(double width, double high) {
		if (width < 0 || high < 0)
			throw new FushuException("长方形的长或宽不能为零。。。");
		// 这里当然也可以用if语句来判断然后给出错误提示,但是在java中这样做是不提倡的;
		// 因为这样写的话错误处理代码和正常流程代码联系非常紧密,阅读性比较差;正真做项目时
		// 如果用if语句,那么if里面将会是一大片处理代码,阅读性非常差;而异常处理Exception的
		// 好处在于可以将异常处理代码和正常流程代码分离开来,当问题发生时,可以不修改正常流程代码
		// 而直接到异常处理代码区修改异常处理代码;
		this.width = width;
		this.high = high;
	}

	public void getArea() {
		System.out.println(width * high);
	}
}

//计算圆面积
class Circle extends Area {
	private double radious;
	public static final double PI = 3.14;

	Circle(double radious) {
		if (radious < 0)
			throw new FushuException("圆半径为负数。。。。");
		this.radious = radious;
	}

	public void getArea() {
		System.out.println(radious * radious * PI);
	}
}

class DoArea {
	public void doArea(Area a) {
		a.getArea();
	}
}

class ExceptionArea {
	public static void main(String[] args) {
		DoArea d = new DoArea();
		d.doArea(new Rect(2.0, 3.6));
		d.doArea(new Circle(-2));
	}
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值