日期:2014-05-20  浏览次数:20998 次

J2SE知识点归纳笔记(四)---Java异常与断言

Java异常与断言


前言


在前面三节的学习中,对于面向对象的编程思想已告一段落了;

从前面的学习我们都知道,Java具有安全,可靠两个优点,一部分原因是因为

Java摒弃了指针这个概念,还有垃圾回收机制;还有一个原因是因为Java提供了异常处理机制

在这一节中,我们将会对异常与断言这两个关键词进行解析!



本节学习路线图:



学习路线解析:

①了解异常是什么东东,熟悉几个常见的异常,学会使用try-catch,finally,throws和throw对异常进行处理;学会自定义异常

②了解断言的好处,以及断言的启动,关闭




异常:


什么是异常?

程序运行过程中出现的不正常现象!例如:除法运算时,除以0,这个就是算术异常

记住:异常时运行时的程序出错,编译时检查的仅仅是语法错误!不运行而来的异常?



为什么会出现异常?

程序运行过程中由于各种因素导致程序运行发生错误,比如用户的错误操作,代码本身错误,系统环境因素等;

在处理异常时需要对异常进行判断,针对不同的异常类型采取不同的处理措施!


异常的分类:


异常处理机制模型



常见的异常信息总结

ArithmeticException 算术异常
ArrayIndexOutOfBoundsException 数组下标越界异常
ArrayStoreException 数组元素类型不兼容eg:为整型数组赋浮点型的数
ClassCastException 类型强制转换异常(精度丢失)
ClassNotFoundException 找不到对应类异常
CloneNotSupportedException 调用clone()方法,但没有实现Cloneable接口(ps:数组默认实现该接口)
EOFException 文件已结束异常
FileNotFoundException 找不到对应文件异常
IllegalAccessException 否问某个类被拒绝时的异常(eg:在别的类中访问private修饰的类)
IndexOutOfBoundsException 下标索引越界异常(eg:数组int a[5],访问a[5]);就会触发该异常,因为下标从0开始
InstantiationException 使用newInstance()方法创建抽象类或借口实例抛出的异常
IOException 输入输出异常
NullPointerException 空指针异常,这个是比较常见的,eg:对象没有实例化直接调用属性或者方法
NumberFormatException 数字格式转换异常,eg:"1+2"这个是字符串,转化为数字就报错了
NoSuchFieldException 字段未找到异常
NoSuchMethodException 方法为找到异常
NoSuchElementException 元素未找到异常(eg:调用StringTokenizer的nextToken()方法可以出现)
SecurityException 安全异常问题,可能需要修改权限
SQLException 数据库操作异常
StringIndexOutOfBoundsException 字符串索引越界异常
MalformedURLException URL配置异常(可能是URL协议,格式,或者路径错误;jar包问题,去掉gnujaxp.jar包引用即可)
UnknowHostException 域名解析出错异常
IllegArgumentException 向方法传递了一个不合法或者不合理的参数
IllegalStateException 违法的状态异常,调用了某个不处于合法调用状态的方法(eg:调用已经销毁的方法)



检验异常与非检验异常


Error类:表示一个程序错误,指的是底层的,低级的,不可以恢复的严重错误;此时的程序一定会退出,因为已经失去了

      程序运行所需的物理环境;我们无法进行处理

Exception类:分为检验异常和非检验异常

RuntimeException及其子类都是非检验异常,其他的异常均为检验异常,需要进行捕获

检验异常:程序代码中需要进行捕获的异常,(try-catch或者throws + try - catch)

非检验异常:因为没有进行必要的检查,由于疏忽或错误引起的异常,一定属于虚拟机内部异常(eg:空指针异常)



异常的处理


异常的捕获


try-catch块

catch块必须和try块一起使用,不能单独使用

代码示例:数组越界异常

package com.jay.example;

/*
 * 该代码演示的使用try-catch来捕获数组越界异常
 * 如果没加try和catch,那么后面的HeHe是不会打印的,因为
 * 因为数组越界程序会直接终止,加了try-catch,如果发生了异常
 * 那么就会执行catch里面的方法;
 * 如果把a[5]改成a[4]木有异常,那么catch块就不会执行了
 * */
public class ExceptionTest1 {
	public static void main(String[] args) {
		int a[] = {1,2,3,4,5};
				
		try
		{
			System.out.println(a[5]);
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			System.out.println("数组越界啦!!!!");
		}
		System.out.println("HeHe");
	}
}

运行截图:



finally块

不能单独使用,需要与try搭配,无论什么情况,finally块中的内容一定会执行,通常在finally块中执行一些系统资源清理和释放的工作

如:文件关闭,数据库关闭等

注意:有特殊!如果在catch块中调用了System.exit(0);方法,那么finally部分的代码不会被执行,因为程序已经终止了


代码示例:算术异常

package com.jay.example;

/*
 * 该代码演示的是finally块的使用
 * 需要跟这一个try,无论异常是否发生
 * 都会执行,只有在catch块中调用了System.exit(0);
 * 方法才能阻止finally执行;
 * 通常是在该方法中完成系统资源的清理释放
 * */

public class ExceptionTest2 {
	public static void main(String[] args) {
		int x = 10;
		int y = 0;
		try
		{
			System.out.println(x/y);
		}
		catch(ArithmeticException e)
		{
			System.out.println("除数不能为0,算术异常!");
		}
		//可自己删掉try中的语句,或者在前面的catch中添加System.exit(0)来测试
		//finally什么时候执行!
		finally
		{
			System.out.println("finally无论是否异常都执行!");
		}
	}
}

运行截图:





多重catch块

就是使用多个catch块,依次捕获不同的异常;

其实只有一个catch块被执行,要把子类异常的catch需放在父类异常的catch前面哦!

package com.jay.example;
/*
 * 该代码演示的是多重catch块的捕获
 * 代码中故意犯了除0,数组下表越界,数字格式三个错误
 * 当程序发生错误了,依次寻找第一个匹配的异常
 * 子类的catch块要放在父类的catch块前面哦!
 * */


public class ExceptionTest3 {
	
	public static void main(String[] args) {
		try
		{
			//现在报算数异常;如果把这部分注释掉就会报数组越界异常
			int a = 1;
			int b = 0;
			System.out.println(a/b);
			
			//如果把这部分注释掉,那么会报数字格式异常
			int c[] = {1,2,3};
			System.out.println(c[3]);
			
			//如果把这部分注释掉,就正常输出了
			int d = Integer.parseInt("a");
			int e = Integer.parseInt("2");
			System.out.println(d + e);
			
			System.out.println("程序木有错误!");
			
		}
		catch(NumberFormatException ex){System.out.println("数字格式异常!");}
		catch(ArithmeticException ex){System.out.println("算数异常,不能除以0!");}
		catch(ArrayIndexOutOfBoundsException ex){System.out.println("数组下标越界异常!");}
		catch(Exception ex){System.out.println("其他异常");}
		
		
	}
}


运行截图:





try-catch块的嵌套

就是try-catch里面又有try-catch,这个和if-else的嵌套差不多,

效果和前面的多重catch块差不多,比较简单,这里就不讲了

			try
			{
				try
				{
					
				}catch(Exception e){}
			}catch(Exception e){}




异常声明


throws回避异常

当一个方法可能会引发某种异常时,但是我们又不想在该方法中对该异常进行处理;

可以用throws将异常抛出,当我们调用该异常时再对异常进行捕获


代码示例:

package com.jay.example;

/*
 * 带代码演示的是使用throws回避方法中可能会出现的异常
 * 等调用方法时再对异常进行捕获处理
 * */

public class ExceptionTest4 {
	
	//再方法这里使用throws回避异常,就是说不在这里对异常进行捕获处理
	//还有这里用static修饰是因为main()方法是静态方法,只能调用类中的静态成员
	public static void show()throws ArrayIndexOutOfBoundsException
	{
		int a[] = {1,2,3};
		System.out.println(a[3]);
	}
	
	public static void main(String[] args) {
		//对方法中的异常进行捕获!
		try{
			show();
		}catch(ArrayIndexOutOfBoundsException ex){System.out.println("数组越界异常!");}
		
	}
}




异常抛出


throw显式引发异常

部分读者可能有个问题:程序没异常不好么?吃饱饭没事做啊,为什么要自己去引发异常?

其实显式抛出异常通常用于程序的调试或者抛出用户自定义异常

自定义异常时用的比较多!


自定义异常


系统提供的异常类不一定能捕获所有的错误异常,

在这种情况下,用户可以根据自己的需要,自定义异常类型

自定义异常注意以下三点:

①自定义异常时,需要继承Exception类

②由于是自定义异常,所以需要使用throw手动抛出自定义异常

③同事需要使用try-catch对异常进行捕获


代码示例:

package com.jay.example;


//继承Exception父类,构造方法中super()里面的
//参数,可以通过MyException对异常进行捕获
class MyException extends Exception
{
	public MyException() {
		super("自定义异常:除数不合规定");
	}
}

public class ExceptionTest5 {
	public static void main(String[] args) {
		int a = 2;
		int b = 1;
		//如果满足一下情况就throw抛出异常,同时要用try-catch进行捕获
		if(b == 0 || b == 1)
		{
			try {
				throw new MyException();
			} catch (MyException e) {
				System.out.println(e.getMessage());
			}
		}
		
	}
}

运行截图:




断言


什么是断言?

jdk 1.4后,引入的Assert(断言)的概念;允许在代码中添加一些合法的语句

以用于调试程序;在assert指定的布尔表达式条件不成立时会会抛出

一个AssertionError对象,直接终止程序的运行!


使用断言的好处?

一种错误处理机制,在程序开发与测试阶段使用;
可以理解为代替,if..else或者try-catch,因为这些东东对程序的性能有一定影响

完成调试后还要将他们删除,如果用断言,则是最低代价


断言的使用:

assert 条件

assert 条件:错误信息

第二种方式,如果前面的条件不成立的话,那么后面的字符串作为AssertionError错误输出信息


断言的开启

默认情况下断言是关闭的,要通过 enableassertions或-ea来启用断言功能


断言的关闭

使用disableassertions或-da来关闭断言功能


代码示例

public class AssertDemo {
	
	static void test(int num)
	{
		//如果num <= 0的话,抛出AssertError,显示错误信息
		assert(num >=0):"传入参数需要大于0";
		System.out.println("参数为正数!");
	}

	public static void main(String[] args) {
		test(-7);
	}
}

运行截图:



代码解析:

判断某个参数是否为正数,通过添加assert对参数进行判断,表达式不成立的话输出后面的错误信息

然后在cmd下调用断言,-ea启动断言,-da关闭断言


总结

在这一节中,我们对Java中的异常处理机制进行了解析,对异常处理模型和常见异常进行了了解

学会了使用try,catch,finally,throws,throw等关键字完成异常捕获,处理,抛出,回避等;

学习了自定义异常的使用;

最后还学习了一下断言的基本用法;使用断言时还有注意一下两点:

①断言失败是致命,不可恢复的

②断言检查仅仅用于程序开发测试阶段

建议还是少用!



好了,这一节就到这里,如有纰漏,错误,好的建议;

请读者指出,不胜感激!O(∩_∩)O谢谢!





1楼u014450015昨天 10:28
博主,我又来了,异常和断言这节写得真的灰常详细啊,够我看几天了,谢谢博主的无私奉献啊!