异常(Exception)

异常(Exception)就是Java程序在运行过程中出现错误,程序编译通过并不代表着在运行时不会出错。

public class ExceptionTest01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a = 1024;
		int b = 0;
		System.out.println(a/b);
	}

}

上面的代码虽然编译能够通过,但是在运行时将会报出ArithmetiExCeption: /by Zero。
0当然不能当做除数的。通过这个异常提示信息可以快速的指导程序的问题,有助于开发者编写出更加健壮的程序,这是异常最主要的作用。

二、异常的分类

异常主要分为: Error、一般性异常、RuntimeException

  • Error : 如果程序出现了 Error,那么将无法恢复,只能重新启动,最典型的Error的异常是:OutOfMemoryError。

  • 一般性异常:出现了这种异常必须在程序里面显示的处理,否则程序无法编译通过
    (除了RuntimeException外其余的Exception均为一般性异常).

  • RuntimeException:此种异常可以不用显示处理,例如被0除异常,java没有要求我们一定要处理。
    (RuntimeException is the superclass of those exceptions that can be thrown during the normal operation of the Java Virtual Machine.)
    在这里插入图片描述
    所有的异常的祖先类是 Throwable ,这个类在java.lang 包下面。

JVM是如何处理异常的

  • main方法自己将该问题处理,然后继续运行

  • 自己没有针对的处理方式,只有交给调用main的jvm处理,jvm有一个默认的异常处理机制。例如上面出现的ArithmeticException,jvm在控制台里面打印出来了异常信息。

三、throws关键字声明异常

throws
throws的作用是声明抛出异常,在方法声明的位置使用throws关键字向上抛出异常。例如下面程序演示了一般性异常,编译无法通过,需要对异常进行处理:

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class ExceptionTest01 {

	public static void main(String[] args)  {
		
		//Object-> throwable -> Exception -> IOException -> FileNotFoundException
		//这句代码的意思是创建文件输入流,读取文件,遇到不认识的类可以查看API。
		FileInputStream fis = new FileInputStream("d:/monkey1024.txt");
	}

}

可以使用throws将异常抛出

public class ExceptionTest01 {

	public static void main(String[] args) throws FileNotFoundException  {
		
		//Object-> throwable -> Exception -> IOException -> FileNotFoundException
		//这句代码的意思是创建文件输入流,读取文件,遇到不认识的类可以查看API。
		FileInputStream fis = new FileInputStream("d:/monkey1024.txt");
	}

}

运行程序,程序编译已经通过,但程序在控制台打印出如下的信息,说明throws抛出的异常由jvm进行了处理:
在这里插入图片描述

深入throws
其实使用throws抛出异常并不是真正的处理异常,而是抛给其调用者去处理,比如你在工作中遇到问题了,交给你的领导去解决,领导如果也不想解决就交给他的领导去解决。在上面程序里面,我们抛出了异常,最后是交给jvm解决,jvm的解决方法就是将错误信息打印至控制台,然后关闭程序。

package com.exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class ExceptionTest01 {

	public static void main(String[] args) throws FileNotFoundException  {
		//抛给调用者,如果都不进行处理的话,最终抛给了main方法
		m1();
	}
	
	
	public static void m1() throws FileNotFoundException {
		//由m2()抛上来的异常,需要在本部中接着处理,如果接着上抛,需要在其调用方法中处理
		m2();
	}
	
	public static void m2() throws FileNotFoundException {
		//由m3()抛上来的异常,需要在本部中接着处理,如果接着上抛,需要在其调用方法中处理
		m3();
	}
	
//	public static void m4() {
//		m3();
//	}
	
	public static void m3() throws FileNotFoundException {
		//错误异常抛给其调用方法 m2();需要在其调用方法中接着处理
		FileInputStream fis = new FileInputStream("d:/monkey1024.txt");
	}

}

这里不是说使用throws时不好,使用throws主要意图是暴露问题,如何解决让调用者决定。

四、使用try-catch捕捉异常

处理异常
可以使用try…catch…处理异常,例如之前的程序使用 try…catch…处理

package com.exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class TryCatchTest {

	public static void main(String[] args) {
		try {
			FileInputStream fis = new FileInputStream("d:/monkey.txt");
			//捕捉FileNotFoundException异常
		} catch (FileNotFoundException e) { //jvm会创建FileNotFoundException的对象,然后将e指向这个对象
			// 如果try里面的代码没有报错,则不会执行catch里面的代码
			e.printStackTrace();//打印出异常信息
		}
		System.out.println("monkey.1023"); //catch后面的语句会正常执行
	}

}

值得注意的是 FileNotFoundException e:jvm会创建FileNotFoundException的对象,然后将e指向这个对象。

捕捉多个异常
可以捕捉多个异常,但是catch里面必须从小类型异常到大类型异常进行捕捉,先捕捉子后捕捉父,最多执行一个catch语句块里面的内容。

package com.exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class TrycatchTest03 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			FileInputStream fis = new FileInputStream("d:/monkey.txt");
		}catch(FileNotFoundException e){//捕捉FileNotFoundException异常
			e.printStackTrace();
		}catch(IOException e) { //捕捉IOException异常
			e.printStackTrace();
		}catch(Exception e) { //捕捉 Exception异常
			e.printStackTrace();
		}

	}

}

jdk7新特性
Jdk7新特性,可以将多个异常放到一个Catch里面:

package com.exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class TryCatchTest04 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
		      System.out.println(1024/0);
		      FileInputStream fis = new FileInputStream("d:/momnkey.txt");
		}catch(ArithmeticException | FileNotFoundException e) {
			System.out.println("124");
		}
		
	}

}

五、finally关键字

finally的特点:
被finally控制的语句体一定会执行,除非在执行finally语句体之前JVM退出(比如System.exit(0)),一般用于关闭资源

finally如何使用?

finally语句块可以直接和try语句块联用:try…finally…(这种用的比较少)
也可以这样使用: try…catch…finally

package com.exception;

public class FinllyTest01 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			System.out.println(1024/0);
		}catch(ArithmeticException e) {
			e.printStackTrace();
		}finally {
			System.out.println("finally中的内容");
		}
	}

}

在这里插入图片描述
即使在方法里面执行了return,finally中的代码也会执行:

public class FinallyTest02 {

	public static void main(String[] args) {
		int i = m1();
		System.out.println(i);
	}
	
	
	public static int m1() {
		int  i = 10;
		try {
			return i ;
		}finally {
			System.out.println("finally中的语句");
		}
	}

}

在这里插入图片描述
只有当finally语句执行之前,JVM退出了,finally才不会执行:

package com.exception;

public class FinallyTest05 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int i = m1();
		System.out.println(i);
	}
	
	public static int m1() {
		try {
			int i = 1024;//try里面的变量在外部是无法被访问的
			System.exit(0);//让jvm退出,所以finally中的语句不会执行
			return i;
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			System.out.println("finally中的语句");
		}
		return 10;
	}

}

六、自定义异常

自定义异常概述
当java里面的异常无法满足开发者的需求时,可以自定义异常。

package com.exception;

public class UserService {
	//注册的方法
	public void register(String name) throws IllegalNameException {
		if(name.length()<6) {
			//需要在这里面抛出非法注册名的异常,不过java里面没这个
			//手动抛出异常
			//注意是throw不是throws
			//使用throw在方法体内抛出异常
		}
		
		//如果代码能执行到此处,证明用户名是合法的
		System.out.println("注册成功!");
	}

}

上面是一个用户注册的代码,如果注册的用户名长度小于6,则需要抛出 一个非法用户名的异常,不过java里面没有异常,这时,开发者可以自定义这个异常 来满足需求。

如何自定义异常

可以看下其他Exception里面的源码进行参考

如果自定义异常是RuntimeException类型的,那就直接继承RuntimeException即可,否则就继承Exception。

继承之后一般提供两个构造方法,如下自定义名为 IllegalNameException的异常。

package com.exception;

public class IllegalNameException extends Exception { //编译时异常

//	public class IllegalNameException extends RuntimeException //运行时异常
	
	 static final long serialVersionUID = -1191129285034127857L;
	 //定义异常一般提供两个构造方法
	 public IllegalNameException() {}
	 
	 //含参构造方法
	 public IllegalNameException(String msg) {
		 super(msg);
	 }

}

使用自定义异常
自定义好异常之后就可以使用了,将上面的代码修改一下:

package com.exception;

public class UserService {
	//注册的方法
	public void register(String name) throws IllegalNameException {
		if(name.length()<6) {
			//需要在这里面抛出非法注册名的异常,不过java里面没这个
			//手动抛出异常
			//注意是throw不是throws
			//使用throw在方法体内抛出异常
			throw new IllegalNameException();
		}
		
		//如果代码能执行到此处,证明用户名是合法的
		System.out.println("注册成功!");
	}

}

关于throw,在方法内部出现某种情况,程序不能继续运行,就用throw把异常对象抛出。
来写一个测试类:
package com.exception;

public class SerciceTest {

public static void main(String[] args) {
	// TODO Auto-generated method stub
	UserService U1 = new UserService();
	try {
		U1.register("123");
	} catch (IllegalNameException e) {
		e.printStackTrace();
	}
	
}}

在这里插入图片描述
throw和throws的区别

throws

  • 用在方法声明后面,跟的是异常类名
  • 可以跟多个异常类名,用逗号隔开
  • 表示抛出异常,由该方法的调用者处理

throw

  • 用在方法体内,跟的是异常对象名
  • 只能抛出一个异常对象名
  • 表示抛出异常,由方法体内的语句处理

猜你喜欢

转载自blog.csdn.net/ZHOUJIAN_TANK/article/details/87902230