Java中的异常


  

1 什么是异常

  前遇到过的异常:
  1、空指针异常, NullPointerException
  2、类型转换异常, ClassCastException
  3、遇到这些异常使程序中断了

  异常就是在程序运行过程中出现不正常现象导致了程序中断

2 异常的类结构

  在Java中, 把经常出现的一些异常现象进行了抽象就形成了异常类
在这里插入图片描述

3 运行时异常的特点

  1、运行时异常就是RuntimeException类及它的子类
  2、运行时不需要预处理, 通过规范代码可以避免

/**
 * 演示运行时异常
 *
 */
public class Test01 {
	public static void main(String[] args) {
//		divide1(10, 2);
		divide1(10, 0); 	//执行语句时, 除数为0,会产生算术异常, 导致了程序中断
		
		divide2(10, 0);
		
		System.out.println("main方法后面的代码");
	}
	
	//定义方法, 计算两个整数相除的结果
	public static void divide1( int x , int y) {
		System.out.println(x + " / " + y + " = " + (x/y) );
	}
	
	//运行时异常,可以通过规范的代码避免
	public static void divide2( int x , int y) {
		//整数相除, 如果除数为0,会产生算术异常
		if ( y == 0 ) { 		//通过判断, 如果除数为0, 给用户一个提示信息, 不再进行计算
			System.out.println("除数不能为0");
			return;
		}
		System.out.println(x + " / " + y + " = " + (x/y) );
	}
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at chapter02.demo01.Test01.divide1(Test01.java:18)
	at chapter02.demo01.Test01.main(Test01.java:9)

Process finished with exit code 1

4 编译时异常特点

  1、编译时异常,也叫受检异常, 即在方法定义时,通过throws声明抛出的异常
  2、在编译前必须对受检异常进行预处理, 即在开发程序时,要指定如果产生了异常应该怎么办

	注意:
		1、编译时异常并不是说在编译阶段发生异常, 所有的异常都是在运行时才会发生.
		2、编译就是把.java编译为.class字节码文件, 编译时要进行语法检查,
	    3、Java语法有很多条, 其中一条语法是说必须对受检异常进行预处理
	  
/**
 * 演示编译时异常
 *
 */
public class Test02 {

	public static void main(String[] args) throws IOException {
		//假设读取d:/abc.txt文件的内容, 需要使用FileInputStream类
		
		FileInputStream fis = new FileInputStream("d:/abc.txt");
		/*
		 * 上行代码出现了语法错误
		 * 		FileInputStream构造方法在定义时, 通过throws语句声明抛出了FileNotFoundException异常, 该异常就是受检异常
		 * 	受检异常就是方法定义时,通过throws声明抛出的异常
		 * 	在调用方法时, 必须对受检异常进行预处理 ,否则编译报错
		 */
		
		m1();
	}

	//定义方法时, 通过throws声明抛出了一个异常, 这个异常就是受检异常
	public static void m1() throws  IOException {
		
	}
}

5 对受检异常进行处理

5.1 try…catch 捕获处理

/**
 * 演示捕获异常
 */
public class Test03 {

	public static void main(String[] args) {
		
		try {
			System.out.println("try代码块中,可能有语句的受检异常需要预处理");
			FileInputStream  fis  = new FileInputStream("d:/abc.txt");
			System.out.println("如果上行代码产生了异常,就直接跳转到catch子句,try代码块后面的代码不再执行");
			
			System.out.println("try代码块中中,可能会有多个受检异常需要预处理, 可以通过多个catch分别捕获");
			fis.read(); 
			
		} catch (FileNotFoundException e) {
			//如果产生 了 文件找不到 异常, 进行处理
			//开发阶段,捕获了异常,一般是打印异常栈跟踪信息, 方便调试
			e.printStackTrace();
		} catch (IOException e) {
			//如果产生了 IO 异常, 进行处理
			//FileNotFoundException继承了IOException,捕获的异常有继承关系, 应该先捕获子异常, 再捕获父异常
			e.printStackTrace();
		}
		
		System.out.println("main方法后面的代码.......");
		
	}

}

5.2 finally子句处理

/**
 * finally子句
 * 	在异常捕获处理中, finally子句不是必须的, 可以这样使用:
 * 		try...catch....,   
 *  	try... catch...finallly,    
 * 		try...finally...
 * 
 * 	一般在finally子句中释放系统资源
 *
 */
public class Test04 {

	public static void main(String[] args) {
		
		try {
			FileInputStream fis = new FileInputStream("d:/def.txt");
			
		} catch ( FileNotFoundException e) {
			e.printStackTrace();
		}finally {
			System.out.println("finally子句");
		}
		
		System.out.println("main...end....");
	}

}

5.3 finally子句

/**
 * finally子句
 *
 */
public class Test05 {

	public static void main(String[] args) {
		
		int x = m1(10);
		
		System.out.println( x );		//10
	}

	private static int m1(int i) { 		//i=10
		try {
			return i;
		} finally {
			i += 10;
			System.out.println(i);
		}
		/*
		 * 程序执行到return  i;时, 并没有执行return语句, 而是把i的值保存到临时变量中
		 * 执行finally子句, 把i的值变为20
		 * 再执行return语句, 返回的不是i现在的值, 而是返回临时变量的值
		 */
	}

}
20
10

Process finished with exit code 0

5.4 throws抛出处理

/**
 * throws抛出处理
 *
 */
public class Test06 {

	//main方法把异常抛出JVM, JVM默认的处理方式是中断程序,打印异常跟踪信息
	public static void main(String[] args)  {
		System.out.println("在main方法中调用m1方法");
		try {
			m1();
		} catch (FileNotFoundException e) {
			//对m1()方法产生的异常捕获后, 不再继续上抛
			e.printStackTrace();
		}
		System.out.println("main方法运行结束");
	}
	

	private static void m1() throws FileNotFoundException {
		System.out.println("在m1方法中调用m2方法");
		m2();
		System.out.println("m1方法运行结束");
	}
 
	//在定义m2方法时, 把方法体中的受检异常声明抛出, 抛出给调用者
	private static void m2() throws FileNotFoundException {
		System.out.println("m2方法开始执行, 调用 FileINputStream");
		FileInputStream fis = new FileInputStream("d:/def.txt");
		System.out.println("m2运行结束 ");
	}

}
/**
 * throws抛出处理
 *
 */
public class Test06 {

	//main方法把异常抛出JVM, JVM默认的处理方式是中断程序,打印异常跟踪信息
	public static void main(String[] args) throws FileNotFoundException {
		System.out.println("在main方法中调用m1方法");
		m1();
		System.out.println("main方法运行结束");
	}
	

	private static void m1() throws FileNotFoundException {
		System.out.println("在m1方法中调用m2方法");
		m2();
		System.out.println("m1方法运行结束");
	}
 
	//在定义m2方法时, 把方法体中的受检异常声明抛出, 抛出给调用者
	private static void m2() throws FileNotFoundException {
		System.out.println("m2方法开始执行, 调用 FileINputStream");
		FileInputStream fis = new FileInputStream("d:/def.txt");
		System.out.println("m2运行结束 ");
	}

}
在main方法中调用m1方法
在m1方法中调用m2方法
m2方法开始执行, 调用 FileINputStream
Exception in thread "main" java.io.FileNotFoundException: d:\def.txt (系统找不到指定的文件。)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.io.FileInputStream.<init>(FileInputStream.java:93)
	at chapter02.demo01.Test06.m2(Test06.java:28)
	at chapter02.demo01.Test06.m1(Test06.java:21)
	at chapter02.demo01.Test06.main(Test06.java:14)

Process finished with exit code 1

6 异常处理的作用

  通过异常处理可以增加程序的键壮性, 鲁棒性(Robust)
  如果没有对异常进行处理,出现了异常会程序中断(崩溃); 进行了异常处理,程序不会中断,还会继续向下执行

7 如何选择捕获处理还是抛出处理

  在编程时,如何选择捕获处理还是抛出处理
  1、一般情况下, 在调用方法时, 如果被调用的方法有受检异常, 选择捕获处理;
  2、在定义方法时, 如果方法体中有受检异常的语句, 可以选择捕获处理, 也可以选择抛出处理,
  3、如果方法体中通过throw抛出一个异常对象,所在方法通过throws声明抛出该异常

8 方法覆盖中的异常处理

  1、方法签名必须相同
  2、返回值类型可以相同,也可以是子类型
  3、访问权限可以相同,也可以更大
  4、异常不能更大,可以更小

/**
 * 作为父类子类重写父类 的方法
 *
 */
public class Father {
	
	public void m1(int x ) {
		
	}
	
	public void m2()  throws IOException{
		
	}

public class Son extends Father{
	//可以重写父类的方法
	@Override
	public void m1(int x) {
		//该方法在父类中没有抛出异常, 重写后也不能抛出异常
	}
	
	@Override
//	public void m2() throws IOException {
//	public void m2() throws FileNotFoundException {
	public void m2()  {
		//父类方法抛出了异常,重写后,可以抛出相同的异常
		//也可以抛出子异常
		//子类方法,也可以不抛出异常
	}
}

9 异常在开发中的作用

//1)定义一个类继承Exception
public class AgeOutOfBoundsException extends Exception {
	//2)一般情况下,只提供两个构造方法
	public AgeOutOfBoundsException() {
		super();
	}
	//有参数的构造方法, 这个String字符串参数就是异常的信息
	public AgeOutOfBoundsException(String message) {
		super(message);
	}

}
public class Person {
	private String name;
	private int age;
	private String gender; 		//性别
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", gender=" + gender + "]";
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	//4)throw所在的方法通过throws声明抛出该异常
	public void setAge(int age) throws AgeOutOfBoundsException {
		//对参数数据进行合理性验证
		if ( age >= 0 && age < 130) {
			this.age = age;			
		}else {
			//年龄不合适, 抛出一个异常
			//3)通过throw抛出一个异常对象
			throw  new AgeOutOfBoundsException("年龄越界");
		}
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	
}

public class Test {

	public static void main(String[] args) {
		//创建对象,直接给对象的字段赋值
/*		Person p1 = new  Person();
		p1.name = "lisi";
		p1.age = 188888; 		//age表示人的年龄,可能会赋一些无效的值
		p1.gender = "男";
		System.out.println( p1 );*/
		
		//创建对象,调用setter方法实现赋值
		Person p2 = new  Person();
		p2.setName("lisi");
		try {
			p2.setAge(188888);
		} catch (AgeOutOfBoundsException e) {
			e.printStackTrace();
		}
		p2.setGender("妖");
		System.out.println( p2 );
		
	}

}
chapter02.demo03.AgeOutOfBoundsException: 年龄越界
	at chapter02.demo03.Person.setAge(Person.java:28)
	at chapter02.demo03.Test.main(Test.java:20)
Person [name=lisi, age=0, gender=妖]

Process finished with exit code 0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值