目录
一、认识异常
1、有关说明
异常是在程序执行期间所发生的事件,这事件中断了程序指令的正常流程。
当方法内发生错误时,该方法将创建一个对象并将其交给运行时系统。 该对象称为异常对象, 包含有关错误的信息,包括错误的类型和发生错误时程序的状态。创建异常对象并将其交给运行时系统称为抛出异常。
强调:异常是由方法抛出的。
例子
import java.util.Scanner;
public class example1{
private static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
// float f=1.2; 检查异常
calculate();
}
//运行时异常
public static void calculate(){
System.out.println("请输入被除数:");
int number1=sc.nextInt();
System.out.println("请输入除数:");
int number2=sc.nextInt();
int result=number1/number2; //当number2输入0时,发生运行时异常,中断后续代码执行
System.out.println(result); //当number2为0时,该行代码不能被执行
}
}
2、异常体系
认识 Throwable
是所有异常的父类,其常用方法如下:
public String getMessage(); //获取异常发生的原因
public void printStackTrace(); //打印异常在栈中的轨迹信息
认识 Error
Error 是一种非常严重的错误,一般程序员是不能够通过编写来实现问题解决的。
认识 Exception
Exception 表示异常的意思,主要是程序员在编写代码时考虑不周导致的问题。异常分为运行时异常和检查异常两大类。
认识 RuntimeException
RuntimeException 表示运行时异常,所有在程序运行时抛出的异常类型都属于 RuntimeException的子类。运行时异常一般来说程序可以自行恢复,不必处理。
认识 检查异常
检查异常是指编译器在编译代码的过程中发现不正确的编码所抛出的异常。
二、异常处理
1、如何处理异常
在Java中,异常的种类很多,如果每种异常类型我们都需要去记住, 这无疑是一件很困难的事。如果能够有一套机制来处理异常,那么将减少程序员在开发时的耗时。Java就提供了一套异常处理机制来处理异常。Java处理异常使用了5个关键字: throw、throws、 try、catch、finally。
2、throw 抛出问题
throw关键字只能在方法内部使用,throw关键字抛出异常表示自身并未对异常进行处理。
语法
throw 异常对象; //通常与 if 选择结构配合使用
例子
import java.util.Scanner;
public class example1{
private static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
// float f=1.2; 检查异常
calculate();
}
//运行时异常
public static void calculate(){
System.out.println("请输入被除数:");
int number1=sc.nextInt();
System.out.println("请输入除数:");
int number2=sc.nextInt();
if(number2==0){
//发生相应异常时,异常情况将输出:"在除法运算中除数不能为0"
throw new ArithmeticException("在除法运算中除数不能为0");
//下面是另一种书写方式:
/**
* ArithmeticException e=new ArithmeticException("在除法运算中除数不能为0");
* throw e;
*/
} //当number2输入0时,发生运行时异常,中断后续代码执行
int result=number1/number2; //当number2为0时,该行代码不能被执行
System.out.println(result); //当number2为0时,该行代码不能被执行
}
}
3、throws 声明可能抛出的异常类型
throws关键字只能应用在方法或者构造方法的定义上对可能抛出的异常类型进行声明,自身不会对异常做出处理,由方法的调用者来处理。如果方法的调用者未处理,则异常将持续向上一级调用者抛出, 直至main()方法为止,如果main()方法也未处理,那么程序可能因此终止。
语法
访问修饰符 返回值类型 方法名 (参数列表) throws 异常类型1, 异常类型2, …… ,异常类型n {
}
例子
import java.util.InputMismatchException;
import java.util.Scanner;
public class example2 {
private static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
int result=calculate();
System.out.println(result);
}
public static int calculate() throws InputMismatchException,ArithmeticException{
int number1=getNumber();
int number2=getNumber();
return number1/number2;
}
public static int getNumber() throws InputMismatchException {
System.out.println("请输入一个整数:");
int number=sc.nextInt();
return number;
}
}
注:throws 可以声明方法执行时可能抛出的异常类型,但方法执行过程中只能抛出一个异常类型,因为单有一个异常类型抛出时,程序会中断后续执行,除非有 try-finally 使用。
4、try-catch 捕获异常
throw和throws关键字均没有对异常进行处理,这可能会导致程序终止。在这种情况下,可以使用try-catch结构来对抛出异常进行捕获处理,从而保证程序能够正常运行。
语法
try {
//代码块
} catch( 异常类型 异常对象名 ){
}
其中 try 表示尝试的意思,尝试执行 try 结构中的代码块,如果执行过程中发生了异常,则交给 catch 语句进行捕获操作。
例子
import java.util.InputMismatchException;
import java.util.Scanner;
public class example3{
private static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
try {
int number=getNumber();
System.out.println(number);
}catch (InputMismatchException e){
e.printStackTrace(); //打印异常轨迹
System.out.println("输入错误,请输入整数");
}
System.out.println("该句会执行"); //尽管前面发生了异常,但这里的代码会执行此行代码
}
public static int getNumber() throws InputMismatchException {
System.out.println("请输入一个整数:");
int number=sc.nextInt();
return number;
}
}
思考:当一个方法抛出多个异常时,如何捕获?
解决如下:
import java.util.InputMismatchException;
import java.util.Scanner;
public class example4 {
private static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
int w=calculate();
System.out.println(w);
}
public static int calculate(){
try {
int number1=getNumber();
int number2=getNumber();
return number1/number2;
} catch (InputMismatchException e){
System.out.println("输入错误,请输入整数");
return 0;
} catch (ArithmeticException e){ //新的catch的()内容不可与前面重复
System.out.println("在除法运算中除数不能为0");
return -1;
}
}
public static int getNumber() throws InputMismatchException {
System.out.println("请输入一个整数:");
int number=sc.nextInt();
return number;
}
}
注:当使用多个catch语句捕获异常时,如果捕获的多个异常对象的数据类型具有继承关系,那么父类异常不能放在前面。
例子如下:
public static int calculate(){
try {
int number1=getNumber();
int number2=getNumber();
return number1/number2;
} catch (Exception e){ //将会报错
System.out.println("输入错误,请输入整数");
return 0;
} catch (ArithmeticException e){ //新的catch的()内容不可与前面重复
System.out.println("在除法运算中除数不能为0");
return -1;
}
}
public static int getNumber() throws InputMismatchException {
System.out.println("请输入一个整数:");
int number=sc.nextInt();
return number;
}
}
public static int calculate(){
try {
int number1=getNumber();
int number2=getNumber();
return number1/number2;
} catch (InputMismatchException e){
System.out.println("输入错误,请输入整数");
return 0;
} catch (Exception e){ //新的catch的()内容不可与前面重复
// 父类在子类后面可执行
System.out.println("在除法运算中除数不能为0");
return -1;
}
}
public static int getNumber() throws InputMismatchException {
System.out.println("请输入一个整数:");
int number=sc.nextInt();
return number;
}
}
5、finally 语句
finally 语句不能单独使用,必须与 try 语句或 try-catch 语句配合使用,表示程序无论是否会发生异常都会执行,主要用于释放内存。但如果在 try 语句或者 catch 语句中存在系统退出的代码,则 finally 语句将得不到执行。
语法
try {
} finally {
}
//或者
try {
} catch( 异常类型 异常对象名 ) {
} finally {
}
例子
public class example5 {
private static int[] numbers={1,2,3,4,5,};
public static void main(String[] args) {
try {
//下面代码可实现系统退出,非0状态码表示异常退出
//System.exit(0);
//可使后面的代码无法执行,直接退出程序
int number=getNumberFromArray(5);
System.out.println(number);
} catch (ArrayIndexOutOfBoundsException e){
System.out.println("数组下标越界");
} finally {
System.out.println("finally需要执行的代码");
//finally里代码必执行,除非有 System.exit(0); 在前
}
}
public static int getNumberFromArray(int index){
return numbers[index];
}
}
三、自定义异常
1、自定义原因
在java中,异常的类型非常的多,要想使用这些异常,首先必须要熟悉它们。这无疑是个巨大的工作量,很耗费时间。如果我们可以自定异常,则只需要熟悉RuntimeException、Exception 和Throwable即可。这大大缩小了熟悉范围。自定义异常还可以帮助我们快速地定位问题。
自定义运行时异常语法
public class 类名 extends RuntimeException { }
自定义检查异常语法
public class 类名 extends Exception { }
例子
package com.scend.exception;
/**
* 用户名不存在异常
*
* 异常名规范:场景描述+Exception
*/
public class UsernameNotFoundException extends Exception{
public UsernameNotFoundException(){}
public UsernameNotFoundException(String msg){
super(msg);
}
}
package com.scend.exception;
/**
* 账号或密码错误异常
*/
public class BadCredentialsException extends Exception{
public BadCredentialsException(){}
public BadCredentialsException(String msg){
super(msg);
}
}
package com.scend.exception;
import java.util.Scanner;
public class Login {
private static Scanner sc=new Scanner(System.in);
public static void main(String[] args) {
System.out.println("请输入账号:");
String username=sc.next();
System.out.println("请输入密码:");
String password=sc.next();
try {
login(username,password);
} catch (UsernameNotFoundException e) {
e.printStackTrace();
} catch (BadCredentialsException e) {
e.printStackTrace();
}
}
public static void login(String username,String password) throws UsernameNotFoundException, BadCredentialsException {
if("admin".equals(username)){
if("123456".equals(password)){
System.out.println("登录成功");
} else {
throw new BadCredentialsException("账号或密码错误");
}
} else {
throw new UsernameNotFoundException("账号不存在");
}
}
}
2、异常使用注意事项
a、运行时异常可以不处理。
b、如果父类抛出了多个异常,子类覆盖父类方法时,只能抛出相同的异常或者是该异常的子集。(与协变返回类型原理一致)。
c、父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出检查异常。此时子类产生该异常,只能捕获处理,不能明抛出。