黑马程序员-----------异常

------<span style="color:#ff6666;"><a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a></span>、期待与您交流! -------

1.异常

1.1异常的描述

/*
异常。
Java运行时期发生的问题就是异常。

Java中运行时发生的除了异常Exception还有错误Error。

异常:通常发生可以有针对性的处理方式的。
错误:通常发生后不会有针对性的处理方式。
	Error的发生往往都是系统级别的问题,都是jvm所在系统发生的并反馈给jvm的。
	无法针对处理,只能修正代码。

*/


class ExceptionDemo 
{
	public static void main(String[] args) 
	{
		int[] arr = new int[1024*1024*100];//OutOfMemoryError 

		System.out.println(arr[0]);
		System.out.println(arr[3]);//该句运行时发生了ArrayIndexOutOfBoundsException,导致程序无法继续执行。程序结束。
		System.out.println("over");
	}
}

1.2异常发生的细节

/*
异常的发生细节。
*/

class Demo
{
	/*
	对给定的数组通过给定的角标获取元素。
	*/
	int getElement(int[] arr,int index)
	{

		/*
		1,没有找到4个角标。运行时发生了问题,这个问题JVM认识。
		这个问题java本身有描述:描述内容有:问题的名称,问题的内容,问题的发生位置。
		既然有这么多的信息。java就将这些信息直接封装到对象中。ArrayIndexOutOfBoundsException
		*/
		int element = arr[index];//throw new ArrayIndexOutOfBoundsException(index);
		return element;
	}
}


class ExceptionDemo2 
{
	public static void main(String[] args) 
	{
		Demo d = new Demo();
		int[] arr = {34,12,67};
		int num = d.getElement(arr,4);//收到 new ArrayIndexOutOfBoundsException(index); 抛出jvm。jvm进行最终处理。将问题的名称,信息,位置都显示屏幕上。
		System.out.println("num="+num);
		System.out.println("over");
	}
}

1.3异常的应用

/*
异常的应用:

在编写程序时,必须要考虑程序的问题情况。
举例:卖水果功能需要传递钱参数,有可能有假币。
所以定义定义程序需要考虑程序的健壮性。

加入一些逻辑性的判断。




*/
class Demo
{
	/*
	对给定的数组通过给定的角标获取元素。
	*/
	int getElement(int[] arr,int index)
	{
		/*
		jvm出了问题,自己打包对象并抛出。
		但是它所提供的信息不够给力。想要更清晰,需要自己写。
		它的抛出不满足我们的要求。准备自己抛。
		*/
		if(arr==null)
		{
			throw new NullPointerException("arr指向的数组不存在");
		}

		if(index<0 || index>=arr.length)
		{
			//该条件如果满足,功能已经无法继续运算。这时 就必须结束功能,并将问题告知给调用者。这时就需要通过异常来解决。
			//怎么用呢?
			//1,创建一个异常对象。封装一些提示信息(自定义)。
			//2,需要将这个对象告知给调用者。怎么告知呢?怎么将这个对象传递到调用者处呢?通过关键字throw就可以完成。 throw 异常对象;
			//3,throw用在函数内,抛出异常对象,并可以结束函数。
			throw new ArrayIndexOutOfBoundsException("错误的角标,"+index+"索引在数组中不存在");
		}

		int element = arr[index];
		return element;
	}
}


class ExceptionDemo3 
{
	public static void main(String[] args) 
	{
		Demo d = new Demo();
		int[] arr = {34,12,67};
		int num = d.getElement(null,2);
		System.out.println("num="+num);
		System.out.println("over");
	}
}

1.4异常原理

//如果在函数内抛出Exception//编译失败,因为编译器在检查语法时发生了错误。
		/*
		该程序已经出现问题,Java认为这个程序本身存在隐患,
		需要捕获或者声明出来(你要么把问题处理,要么把问题标识出来让调用知道)
		*/
//		throw new Exception();

		/*
		为什么抛出RuntimeException,不需要捕获,不要声明呢?
		不是功能本身发生的异常,而是因为比如调用者传递参数错误而导致功能运行失败。
		这时也是问题,需要通过异常来体现,但是这个异常不要声明出来的。
		声明的目的是为了让调用者进行处理。
		不声明的目的是不让调用者进行处理,就是为了让程序停止,让调用者看到现象,并进行代码的修正。★★★★★

		原理异常分两种:
		1,编译时异常:编译器会检测的异常。
		2,运行时异常:编译器不会检测的异常。不需要声明。声明也可以,如果声明了,无外乎就是让调用者给出处理方式。
		ArrayIndexOutOfBoundsException
		IllegalArgumentException
		NullPointerException
		ClassCastException


class Demo
{
	void show()
	{
	
		throw new RuntimeException();
	}
}

class ExceptionDemo6 
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}
<h3>1.5声明和捕获</h3>

/*
声明和捕获。

声明:将问题标识出来,报告给调用者。
如果函数内通过throw抛出了编译时异常,而捕获,那么必须通过throws进行声明,让调用者去处理。

捕获:Java中对异常有针对性的语句进行捕获。
语句:
try
{
	//需要被检测的语句。
}
catch(异常类 变量)//参数。
{
	//异常的处理语句。
}
finally
{
	//一定会被执行的语句。
}

*/


class Demo
{
	/*
	如果定义功能时有问题发生需要报告给调用者。可以通过在函数上使用throws关键字进行声明。

	*/
	void show(int x)throws Exception
	{
		if(x>0)
			throw new Exception();
		else
			System.out.println("show run");
	}
}


class ExceptionDemo7 
{
	public static void main(String[] args)//throws Exception//在调用者上继续声明。 
	{
		Demo d = new Demo();
		try
		{
			d.show(1);//当调用了声明异常的方法时,必须有处理方式。要么捕获,要么声明。
		}
		catch (Exception ex)//括号中需要定义什么呢?对方抛出的是什么问题,在括号中就定义什么问题的引用。
		{
			System.out.println("异常发生了");
		}
		System.out.println("Hello World!");
	}
}

1.6自定义异常

1 为什么要自定义异常?

2 自定义异常到底该继承谁?

3 Exception和RuntimeException的区别?

                                     编译时异常,运行时异常。

4 这两个异常到底什么时候用?

                                     问题发生时,需要调用者给出具体的处理方式吗?

                                               需要,编译时异常。

                                               不需要,运行时异常
class NoAgeException extends RuntimeException
{
	/*
	为什么要定义构造函数,因为看到Java中的异常描述类中有提供对问题对象的初始化方法。
	*/
	NoAgeException()
	{
		super();
	}

	NoAgeException(String message)
	{
		super(message);// 如果自定义异常需要异常信息,可以通过调用父类的带有字符串参数的构造函数即可。
	}
}

class Person
{
	private String name;
	private int age;
	/*
	构造函数到底抛出这个NoAgeException是继承Exception呢?还是继承RuntimeException呢?
	继承Exception,必须要throws声明,一声明就告知调用者进行捕获,一旦问题处理了续执行。
	但是如果使用到了Person对象的数据,导致都失败的。调用者的程序会继
	继承RuntimeExcpetion,不需要throws声明的,这时调用是不可能编写捕获代码的,因为调用根本就不知道有问题。
	一旦发生NoAgeException,调用者程序会停掉,并有jvm将信息显示到屏幕,让调用者看到问题,修正代码。哦耶。

	*/


	Person(String name,int age)//throws NoAgeException
	{
		//加入逻辑判断。
		if(age<0 || age>200)
		{
			throw new NoAgeException(age+",年龄数值非法");
		}
		this.name = name;
		this.age = age;
	}
	//定义Person对象对应的字符串表现形式。覆盖Object中的toString方法。
	public String toString()
	{
		return "Person[name="+name+",age="+age+"]";
	}
}
class ExceptionDemo8
{
	public static void main(String[] args) 
	{
//		try
//		{
			Person p = new Person("xiaoming",20);
			System.out.println(p);
//		}
//		catch (NoAgeException ex)
//		{
//			System.out.println("异常啦");
//		}

		
		System.out.println("over");
	}
}

1.7throw和throws的区别

/*
throw和throws的区别?

1,throw用在函数内。
	throws用在函数上。
2,thorw抛出的是异常对象。
	throws用于进行异常类的声明,后面异常类可以有多个,用逗号隔开。



*/

class Demo
{
	void show()throws Exception
	{
		throw new Exception();
	}
}

class  
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}

1.8异常的细节

 

         1,一个功能可以声明多个异常。

         2,对于多个异常声明,必须对应多个catch针对性处理。

         3,catch中处理不了的异常可以继续抛出,也可以转换抛出。

 

/*
案例二:毕老师用电脑讲课。
两个对象:
	老师:
		属性:姓名。
		行为:讲课。
	电脑:
		行为:运行。

考虑问题。
1,电脑蓝屏-->异常。

2,电脑冒烟-->异常。

*/
// 可以声明,让调用给出处理方式。
class LanPingException extends Exception
{
	LanPingException()
	{
		super();
	}
	LanPingException(String message)
	{
		super(message);
	}
}

class MaoYanException extends Exception
{
	MaoYanException()
	{
		super();
	}
	MaoYanException(String message)
	{
		super(message);
	}
}
/*
讲课中冒烟,问题可以临时解决,是冒烟问题没有直接处理,所以就使用throws声明。
但是发现,这个问题不应该属于讲课的问题。调用讲课方法的调用者是处理不了这个冒烟问题的。
该调用者能处理的应该是冒烟导致的课程进行不下去的问题。
应该在列出一个异常。课时停止异常。

*/
class NoPlanException extends Exception
{
	NoPlanException()
	{
		super();
	}
	NoPlanException(String message)
	{
		super(message);
	}
}


class NoteBook
{
	private int state = 2;
	public void run()throws LanPingException,MaoYanException//方法上可以通过throws声明多个异常。
	{
		System.out.println("笔记本电脑运行");
		if(state == 1)
			throw new LanPingException("电脑蓝屏了");

		if(state == 2)
			throw new MaoYanException("电脑冒烟了");
	}
	public void reset()
	{
		state = 0;
		System.out.println("电脑重启");
	}
}
class Teacher
{
	private String name;
	private NoteBook book;
	Teacher(String name)
	{
		this.name = name;
		book = new NoteBook();
	}
	//讲课。
	public void prelect()throws NoPlanException
	{
		/*
		调用到了声明异常的方法,在这里到底是捕获好呢?还是声明好呢?
		有具体的捕获处理方式吗?有,那就捕获,没有,那么声明。
		我可以处理,重启就可以了,重启是电脑的功能。
		*/
		try
		{
			book.run();//对于声明多个异常的方法,在处理,需要定义多个catch与之对应。
		}
		
		catch (LanPingException e)//LanPingException e = new LanPingException("电脑蓝屏了");
		{
			//重启。
			System.out.println(e.toString());//异常的名称+异常的信息。
//			e.printStackTrace();
			book.reset();
		}
		catch(MaoYanException e)//MaoYanException e = new MaoYanException("电脑冒烟了");
		{
			System.out.println(e.toString());
			test();
			//冒烟问题没有解决,继续声明throws出去。
//			throw e;
//			new 电脑维修部(book);//去修电脑。
//			book = new NoteBook();
			throw new NoPlanException(e.getMessage()+",课时停止");//异常转换。


		}
		System.out.println(name+"....讲课");
	}
	//留练习。
	public void test()
	{
		System.out.println("做练习");
	}
}

class ExceptionTest2 
{
	public static void main(String[] args) 
	{
		Teacher t = new Teacher("毕老师");
		try
		{
			t.prelect();
		}
		catch (NoPlanException e)
		{
			System.out.println(e.toString());
			System.out.println("换老师");
		}
		
		System.out.println("Hello World!");
	}
}

1.9  finally语句

 

需求:有一些特定的代码无论异常是否发生,都需要执行。

因为异常会引发程序跳转,导致有写语句执行不到。无法满足这个需求。

异常捕获处理时java提供解决方案。

try catch finally

finally就是解决这个问题的,这个代码块中存放的代码都是一定会被执行的。
应用场景;


定义一个功能往数据库中添加数据。

void add(Data data)throws NoAddException
{
	//1,连接数据库。
	try{
	//2,添加数据。//添加数据时发生了异常情况。throw new SQLException();程序跳转,就执行不到断开连接。
				//而断开连接必须要执行,因为不执行,连接资源在浪费。
				//无论是否发生问题,都需要执行断开连接的动作,从而释放资源。
	}catch(SQLException e)
	{
		//解决数据库的问题。
		//同时将问题告诉调用者。
		throw new NoAddException();
	}
	finally
	{
		//3,断开连接。
	}

}

总结:finally到底什么时候用?

只要程序中使用到了具体的资源(数据库连接,IO资源,网络连接socket等)

需要释放,都必须定义在finally中。你在定义程序,只要问题发生与否,

指定程序都需要执行时,就定义finally中。

 

1.10  try catchfinally 组合方式

/*
try catch finally 组合方式:

1,
try catch : 对代码进行异常检测,并对检测的异常传递给catch处理。
			异常捕获处理。
void show()//不用throws 
{
	try{
	throw new Exception();
	}catch(Exception e)
	{
	
	}
}

2,
try finally : 对代码进行异常检测,检测到异常后因为没有catch,所以一样会被默认jvm抛出。
			异常是没有捕获处理的。但是功能所开启资源需要进行关闭,所有finally。
			只为关闭资源。

void show()//需要throws 
{
	try{
	throw new Exception();
	}finally
	{
	
	}
}

3,
try catch finally
检测异常,并传递给catch处理,并定义资源释放。

4,try catch1 catch2 catch3......

*/


1.11异常在继承或者实现中的使用细节

/*
异常在继承或者实现中的使用细节:★★★★★
1,子类覆盖父类方法时,如果父类的方法声明异常,子类只能声明父类异常或者该异常的子类,或者不声明。
2,当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集。
3,当被覆盖的方法没有异常声明时,子类覆盖时时无法声明异常的。
	举例:父类存在这种情况,接口也有这种情况,
	问题:接口中没有声明异常,而实现的子类覆盖方法时发生了异常,怎么办?
		 无法进行throws声明,只能catch的捕获。万一问题处理不了呢?catch中继续throw抛出,但是只能将异常转换成RuntimeException子类抛出。

	Interface Inter
	{
		public void show();
	}
	class Demo implement Inter
	{
		public void show()
		{
			try{
				throw new Exception();
			}catch(Exception e)
			{
				code...;
				throw new RuntimeException("");// 告知调用者问题所在。
			}
		}
	}


Exception
	|--AException
		|--AAException
	|--BException
*/
class AException extends Exception
{
}
class BException extends Exception
{
}
class AAException extends AException
{
}


class Fu
{
	void show()
	{
		
	}
}
/*
class Tool
{
	void method(Fu f)//Fu f = new Zi();
	{
		try
		{
			f.show();
		}
		catch (AException ex)//AException ex = new AAException();
		{
		}
	}
}
Tool t = new Tool();
//t.method(new Fu());
t.method(new Zi());
*/

class Zi extends Fu
{
	void show()throws RuntimeException
	{
		
	}
}


class ExceptionDemo11 
{
	public static void main(String[] args) 
	{
		Zi z = new Zi();
		try{
		z.show();
		}catch(RuntimeException e)
		{}
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值