文章目录
什么是异常
异常本质上是程序上的错误。包括编译时和运行时的错误。
在编译期间出现的错误有编译器帮助我们一起修正,然而运行期间的错误便不是编译器力所能及了,这一部分的错误就是我们程序员关注的焦点。
异常的分类
- Throwable有Erro和Exception两个子类。
- Error是程序无法处理的错误,大多错误与代码编写者无关,而表示代码运行时虚拟机出现的错误,如虚拟机运行错误
。这些错误不在应用程序的控制和处理能力之内,因此我们在编写程序时不需要关注这类异常。 - Exception是程序本身可以处理的异常,包括编译时异常和运行时异常。
- 编译时异常(checked Exception)是编译器要求必须处置的异常,否则编译无法通过:是RuntimeException及其子类之外,其他Exception类的子类,常见IOException、SQLException。
- 运行时错误(unchecked Exception))是编辑器不强制处置的异常,可以选择性进行捕获处理,也可以不处理,照常编译通过:包含是RuntimeException及其子类.。如NullPointerException、IndexOutOfBoundsException。
在java应用程序中,异常处理机制为:1、捕捉异常 2、抛出异常
try-catch
对于异常捕捉,有以下四种方式。
(1)、catch块空白 不处理
package 异常;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午4:00:12
*/
public class try_catch {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}catch (Exception e) {
/*
* 异常处理:java.util.InputMismatchException
* 1、空白 不处理
*
*/
}
System.out.println("结束使用");
}
}
(2)、自定义异常处理
package 异常;
import java.util.Scanner;
import com.sun.org.apache.bcel.internal.generic.NEW;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午4:00:12
*/
public class try_catch {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}catch (Exception e) {
// 2、自定义异常处理
System.out.println(new Exception("代码有异常!!") );
}
System.out.println("结束使用");
}
}
(3)、打印异常信息
package 异常;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午4:00:12
*/
public class try_catch {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}catch (Exception e) {
// 制造异常:java.lang.ArithmeticException: / by zero
//3、打印异常
//System.out.println(e.toString());// java.lang.ArithmeticException: / by zero
//System.out.println(e.getMessage());// 输出异常后的内容: / by zero
//System.out.println(e.getClass());// class java.lang.ArithmeticException
e.printStackTrace();//向控制台输出异常信息
}
System.out.println("结束使用");
}
}
上述代码,Exception是ArithmeticException的父类,try处抛出的异常对象被catch捕获用Exception e接收,而ArithmeticException是重写了父类的tosString()方法 因此输出:java.lang.ArithmeticException: / by zero
(4)、抛出异常对象
package 异常;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午4:00:12
*/
public class try_catch {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}catch (Exception e) {
//4、抛出异常:将异常信息抛给调用者 这里虚拟机调用 了main方法
//因此虚拟机(1)、向控制台输出异常堆栈信息 (2)、中断程序
throw e;
}
System.out.println("结束使用");
}
}
上述代码,将异常信息抛给调用者,这里虚拟机调用 了main方法,因此虚拟机(1)、向控制台输出异常堆栈信息 (2)、中断程序
System.out.println(“结束使用”)不打印的情况
什么时候不执行代码最后的System.out.println(“结束使用”)呢?有以下几种情形:
1)、catch语句块里使用throw e处理时,如上。
2)、catch语句块中没有正常捕获到异常
3)、catch语句块出现return
2)、catch语句块中没有正常捕获到异常
package 异常;
import java.util.InputMismatchException;
import java.util.Scanner;
/*
System.out.println("结束使用")什么时候不执行:
(1)、catch语句块里使用throw e处理时
(2)、catch语句块中没有正常捕获到异常
(3)、catch语句块出现return
*
*/
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午4:00:12
*/
public class try_catch {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}catch (InputMismatchException e) {
e.printStackTrace();
}
System.out.println("结束使用");
}
}
上述代码,输入制造的是ArithmeticException异常,而try-catch要捕获的是InputMismatchException异常,因此无法进行正确捕获,程序中止。
3)、catch语句块出现return
package 异常;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午4:00:12
*/
public class try_catch {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}catch (Exception e) {
//3)、catch语句块出现return
return;
}
System.out.println("结束使用");
}
}
try-catch多分支异常捕获
package 异常;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午6:01:36
*/
/*
* 多分支捕获异常:catch块应按先子类异常再父类异常的顺序捕获
*/
public class try_catch_finally {
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}catch (InputMismatchException e) {//捕获非整数输入异常
System.out.println(new Exception("非整数输入异常"));
}
catch (ArithmeticException e) {//捕获分母为0的异常
System.out.println(new Exception("分母为0的异常"));
}catch (Exception e) {
System.out.println(new Exception("其他异常"));
}
System.out.println("结束使用");
}
}
try语句块出现异常且catch块捕获到
try语句块出现异常且catch块没有正确捕获到
package 异常;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午4:00:12
*/
public class try_catch {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}catch (InputMismatchException e) {
e.printStackTrace();
}
System.out.println("结束使用");
}
}
可以看到,与前面讲的一样,没有正确捕获,后面的“结束使用”语句不输出。
try-catch-finally
如果希望System.out.println(“结束使用”)执行,则可以使用finally关键字。
(1)、不论是否有异常被捕获,都会执行finally语句
package 异常;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午6:01:36
*/
/*
* 多分支捕获异常:catch块应按先子类异常再父类异常的顺序捕获
*/
public class try_catch_finally {
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}
catch (ArithmeticException e) {//捕获分母为0的异常
System.out.println(new Exception("分母为0的异常"));
}
finally {
System.out.println("结束使用");
}
}
}
1)、发生异常,且catch块未正确捕获
2)、发生异常,且catch块正确捕获
可以发现,上述代码不论异常是否被正确捕获,finally关键字的内容都会执行。
3)、使用System.exit(1)中止虚拟机调用
package 异常;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月22日 下午6:01:36
*/
/*
* 多分支捕获异常:catch块应按先子类异常再父类异常的顺序捕获
*/
public class try_catch_finally {
public static void main(String[] args) {
Scanner reader=new Scanner(System.in);
System.out.println("---------开始使用计算器----------");
try {
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
System.out.println("商:"+a/b);
}
//若想两个异常一起写:ArithmeticException |InputMismatchException e
catch (ArithmeticException e) {//捕获分母为0的异常
System.out.println(new Exception("分母为0的异常"));
System.exit(0);//若正确捕获异常 运行至此处执行System.exit(1)执行使得虚拟机中止便不会执行finally的代码
}
finally {
System.out.println("结束使用");
}
}
}
throws和throw
上面讲到,对于异常可以使用"throw 一个对象"来抛出,也可以用"throws 可能发生异常的类 "来告知调用者可能会发生的异常,由调用者负责对异常进行处理。
检查时异常
(1)、利用throw制造检查时异常,且使用throws抛出异常
package 异常;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月23日 上午8:08:58
* 类说明
*/
public class throw_ {
public static void devide() throws Exception {
System.out.println("---------开始使用计算器----------");
Scanner reader=new Scanner(System.in);
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
if(b==0) {
//(1)制造检查时异常:除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。
//这种异常编译器要求强制处置,要么try-cathch,要么在方法名后面抛出。
throw new Exception();
}else {
System.out.println(a/b);
}
System.out.println("结束使用");
}
public static void main(String[] args) throws Exception {
devide();
System.out.println("-----------");
}
}
上面代码中,devide()方法里 使用throw new Exception()制造了编译时异常,所以devide不得不进行 异常机制 处理,这里用了throws关键字将异常抛给了调用者,当然也可以使用try-catch进行捕获,接着调用者mian()继续使用throws Exception将异常抛给了虚拟机,虚拟机无处可抛了,继续要处理,就向控制太输出堆栈异常信息同时中断程序。
(2)、利用throw制造检查时异常,且使用try-catch捕获异常
package 异常;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月23日 上午8:08:58
* 类说明
*/
public class throw_ {
public static void devide() throws Exception {
System.out.println("---------开始使用计算器----------");
Scanner reader=new Scanner(System.in);
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
if(b==0) {
throw new Exception();
}else {
System.out.println(a/b);
}
System.out.println("结束使用");
}
public static void main(String[] args) {
try {
devide();
} catch (ArithmeticException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("-----------");
}
}
可以看到 ,在 main()中使用try-catch进行捕获,print("-----------------------")正常输出。
运行时异常
(1)、利用throw制造运行时异常,且使用throws抛出异常
package 异常;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月23日 上午8:08:58
* 类说明
*/
public class throw_ {
public static void devide() throws ArithmeticException{//throws ArithmeticException 可以不加
System.out.println("---------开始使用计算器----------");
Scanner reader=new Scanner(System.in);
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
if(b==0) {
//制造运行时异常:可以根据需要进行异常机制处理 不强制
throw new ArithmeticException();
}else {
System.out.println(a/b);
}
System.out.println("结束使用");
}
public static void main(String[] args) throws ArithmeticException {
devide();
System.out.println("-----------");
}
}
上面代码,devide()使用throws关键字抛出异常,告知调用者可能发生的异常类型,由调用者负责对异常进行处理。由于主函数main()对devide()没有进行异常的机制的捕获,而是抛给了虚拟机,所以当发生异常时就中断了程序。
(2)、利用throw制造运行时异常,且使用try-catch抛出异常
package 异常;
import java.util.Scanner;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月23日 上午8:08:58
* 类说明
*/
public class throw_ {
public static void devide(){
System.out.println("---------开始使用计算器----------");
Scanner reader=new Scanner(System.in);
System.out.println("请输入第一个数");
int a=reader.nextInt();
System.out.println("请输入第二个数");
int b=reader.nextInt();
if(b==0) {
//制造运行时异常:可以根据需要进行异常机制处理 不强制
throw new ArithmeticException();
}else {
System.out.println(a/b);
}
System.out.println("结束使用");
}
public static void main(String[] args) {
try {
devide();
}catch (ArithmeticException e) {
e.printStackTrace();
}
System.out.println("-----------");
}
}
}
上面代码,使用try catch对devide抛出的异常进行捕获机制管理,所以后面的print("------------------")正常输出。
throws和throw区别:
(1)、声明位置不同:throw在方法内抛出异常对象,而throws在方法体抛出异常类型。
(2)、作用不同:
throw:异常出现的源头
throws:在方法的声明处告诉调用者可能发生的异常,由调用者负责处理
重载、重写方法的异常
方法重载,异常不相关。
方法重写,子类异常类型必须是父类异常的或者父类异常的子类。
自定义异常:
自定义异常类MyException:
package 异常;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月23日 下午1:10:35
*/
public class MyException extends Exception {
public MyException() {
}
public MyException(String message) {
super(message);
System.out.println("这是自定义异常类MyException!");
}
}
测试类:Test
package 异常;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月23日 下午1:15:04
* 类说明
*/
public class Test {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String name;
private int age;
public Test(String n,int a) throws MyException {
setName(n);
if(a<0) {
throw new MyException("年龄不能设置为负数");
}else
setAge(a);
}
public static void main(String[] args) throws MyException {
Test test=new Test("JohnnyLin", -1);
}
}
因为MyException继承自Exception,为unexcepted Exception,编译器不通过,需强制处理。
自定义异常:MyException2
package 异常;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月23日 下午1:22:21
* 类说明
*/
public class MyException2 extends RuntimeException {
public MyException2() {
}
public MyException2(String mesage) {
super(mesage);
System.out.println("这是自定义异常MyException2");
}
}
测试类:Test
package 异常;
/**
* @author JohnnyLin
* @version Creation Time:2020年9月23日 下午1:15:04
* 类说明
*/
public class Test {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String name;
private int age;
public Test(String n,int a) {
setName(n);
if(a<0) {
throw new MyException2("年龄不能设置为负数");
}else
setAge(a);
}
public static void main(String[] args) throws MyException {
Test test=new Test("JohnnyLin", -1);
}
}