java异常处理机制

java异常处理机制

  • 当程序中抛出一个异常后,程序从程序中导致异常的代码处跳出,java虚拟机检测寻找和try关键字匹配的处理该异常的catch块,如果找到,将控制权交到catch块中的代码,然后继续往下执行程序,try块中发生异常的代码不会被重新执行。如果没有找到处理该异常的catch块,在所有的finally块代码被执行和当前线程的所属的ThreadGroup的uncaughtException方法被调用后,遇到异常的当前线程被中止。比如手机app的闪退。
  • java异常结构中定义有Throwable类,Exception和Error是其派生的两个子类。其中Exception表示由于网络故障、文件损坏、设备错误、用户输入非法等情况导致的异常;而Error表示java运行时环境出现的错误,例如:JVM内存资源耗尽等。

tyr-catch块

  • 语法定义:

    try{ 代码片段 }catch(Exception e){ 代码段 }catch(){ }...

  • 每个try语句块可以定义多个catch,当不同的异常我们有不同的处理手段时,可以分别捕获这些异常并处理。

  • 最后一个catch处理Exception,可以避免因为一个未捕获的异常导致程序中断

finally

  • finally块是异常处理机制的最后一块,可以直接跟在try块之后,或者最后一个catch之后
  • finally是必走的程序。只要代码执行到try当中,无论try语句块中的内容是否出现异常,finally块的代码必定执行。
  • 通常在finally语句中可以进行资源的释放工作,如关闭打开的文件、删除临时文件等。

比如IO操作完的关闭就可以放在finally中,以确保执行


public static void main(String[] args) {
		FileOutputStream fos = null;//finally和try是两块作用域,若声明在try里finally里调用fos.close会报错,所以声明在外面
		try {
			fos = new FileOutputStream("fos.txt");
			fos.write(1);
		}catch(IOException e) {
			System.out.println("出错了");
		}finally {
			try {//这里调用close也有可能出异常,所以也要写在异常处理块中
				if(fos!=null)//因为最开始fos赋值为空,如果fos赋值的时候出错了,fos值是null
				fos.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
  • JDK7出现后,有一个特性:自动关闭。在try后面可以跟一个小括号,里面放的一般是继承了closeable的类(也就是有close功能的),不必再写finally代码段,这样编译时会自动添加。

  • 下面这段代码编译后会自动补全和上面的一样

public static void main(String[] args) {
		try (
				
				FileOutputStream fos = new FileOutputStream("fos.txt");
				){
			fos.write(1);
		}catch(IOException e){
			System.out.println("出错了");
		}
	}

小题目

下面代码的运行结果是什么?

public static void main(String[] args) {
		System.out.println(test("0")+","+test(null)+","+test(""));
	}
	public static int test(String str) {
		try {
			return str.charAt(0)-'0';
		}catch(NullPointerException e) {
			return 1;
		}catch(Exception e) {
			return 2;
		}finally {
			return 3;
		}
	}

返回结果3,3,3

return的执行过程分两步:

  • 1,jvm在执行有返回值的方法时,会自动声明一个相应类型的变量来储存返回值,这里就是int,当return 时,先把后面的值赋给int变量.
  • 2,第二步跳过后面的语句结束方法,但是return在try块里,结束前需要走一遍finally,所以finally里的return重新给int变量赋了个值
  • 3.finally必走,finally里一旦写了return,之前的return都不会生效,这是要注意的

throw

  • 当程序发生错误而无法处理的时候,会抛出对应的异常对象,除此之外,再某些时刻,我们可能会想要自行抛出异常,例如在异常处理结束后,再将异常抛出,让下一层异常处理块来捕捉,若想要自行抛出异常,可以使用throw关键字,并生成指定的异常对象后抛出

throw new ArithmeticException(String message);

  • new 后面是异常名字,括号里是异常时的提示信息。
    -子类重写父类含有的throws声明异常抛出的方法时对该方法的重写规则:

throws

  • 当我们调用一个含有throws声明异常抛出的方法时,编译器要求我们必须处理这个异常,否则编译不通过。
  • 处理异常的方式有两种:
    1. 使用try——catch主动处理这个异常
    2. 再当前方法上继续使用throws声明抛出。
      具体使用哪种处理方式取决于实际情况,看该异常应当由谁解决。

比如在某个方法中可能因某些错误而引发异常,但是不希望直接在这个方法中处理这些异常,而希望调用它的这个方法来统一处理,这时候就可以使用throws

  • 当一个方法中使用throw抛出一个异常时,就要在当前方法声明的同时使用throws声明该异常的抛出,只有抛出RuntimeException及其子类异常时不强制要求,否则编译不通过
    -子类重写父类含有的throws声明异常抛出的方法时对该方法的重写规则:
    • 可以什么都不抛
    • 可以抛父类异常的其中几个
    • 可以抛出父类方法抛出异常的子类型异常
    • 不允许抛出额外异常(与父类异常不同,且没有继承关系)
    • 允许抛出父类方法抛出异常的子类异常,但是不可以抛父类异常的父类异常
      例如:
	public class ThrowsDemo2 {
	public void dosome()throws IOException ,AWTException{
		
	}
	}
	class Son extends ThrowsDemo2{
	可以什么都不抛
		public void dosome() {
		}
	可以抛父类异常的其中几个
	public void dosome()throws IOException {
			
		}
	可以抛出父类方法抛出异常的子类型异常
	public void dosome()throws FileNotFoundException {
			
		}
	不允许抛出额外异常(与父类异常不同,且没有继承关系)
	public void dosome()throws SQLException {
			
		}
	允许抛出父类方法抛出异常的子类异常,但是不可以抛父类异常的父类异常
	public void dosome() throws Exception{
			
		}
	}

JAVA异常API

java异常可以分为可检测异常,非检测异常:

  • 可检测异常: 可检测异常经编译器验证,对于声明抛出异常的任何方法,编译器将强制执行处理或声明规则,不捕捉这个异常,编译器就不通过,不允许编译。
  • 非检测异常:非检测异常不遵循处理或声明规则。在产生此类异常时,不一定非要采取任何适当操作,编译器不会检查是否已经解决了这样一个异常。非检测异常只有一个:RuntimeException

RuntimeException

  • RuntimeException类属于非检测异常,因为普通JVM操作引起的运行时异常随时可能发生 ,此类异常一般是由特定操作引发。但这些操作在java应用程序中会频繁出现。因此他们不受编译器检查与处理或声明规则的限制。
  • 常见的RuntimeException
    • IllegalArgumentException
      抛出的异常表明向方法传递了一个不合法或不正确的参数。
    • NullPointerException
    • ArrayIndexOutOfBoundsException
    • ClassCastException
      当试图将对象强制转换为不是实例的子类时,抛出该异常
    • NumberFormatException

Exception常用API

  • printStackTrace()跟踪异常事件发生时堆栈中执行的内容
    • 定义:
    void printStackTrace()
    try{}catch(){
    	e.printStactTrace();//输出执行堆栈信息
    	}
    
  • getMessage()得到有关异常事件的信息
  • getCause
    • 很多时候,当一个异常由另一个异常导致异常而被抛出的时后,java库和开放源代码会将一种异常包装成另一种异常。这是,日志记录和打印根异常就变得非常重要。java异常类提供了getCause()方法来检索导致异常的原因,这些可以对异常根层次的原因提供更多的信息。
      该java实践对代码的调试或故障排除有很大的帮助。另外,如果要把一个异常包装成另一种异常,构造一个新异常就要传递原异常。

自定义异常:

通常使用自定义异常来定义业务逻辑问题

  • 语法:class[自定义的异常类名] extends Exception{}
  • 自定义异常是一个类
  • 自定义异常类必须继承一个已存在的异常类
  • 类中最好有父类的所有构造函数(eclipse-source可以快捷生成),以方便设计,比如设计错误提示信息message

你可能感兴趣的:(学习日志)