知识点模块: 一.异常概述: 二.异常的处理方式 1.JVM默认处理方式 2.throw关键字抛出异常 3.throws关键字异常声明 4.编译时异常与运行时异常 5.try...catch...finally 6.异常在编译时的使用规则 7.异常体系的方法 8.自定义异常 详细代码在下面的gitee链接的Day21文件中 JavaSE: Java基础 一.异常概述: 什么是异常? 异常指的是java程序在运行期间出现的问题 异常的设计思想: 由于java是纯面向对象语言,因此Java将程序中可能出现的问题都映射成了Java类 映射的Java类最终形成了异常体系 异常体系: Thorwable Exception:java程序中出现的异常都是Excettion类或者Exception的子类 Error:程序中出现的错误,例如:服务器宕机,内存溢出 我们一般改代码或者修改硬件来解决 二.异常的处理方式 1.JVM默认处理方式 参照图解 2.throw关键字抛出异常 手动处理异常 我们可以通过throw关键字抛出一个异常对象 格式:throw new 异常类的构造方法 注意事项: 一旦执行throw new 异常类的构造方法;语句,该语句下面的代码都不在执行 throw new 异常类的构造方法下面不能有任何语句马,因为永远执行不到
/*
手动处理异常
我们可以通过throw关键字抛出一个异常对象
格式:throw new 异常类的构造方法
注意事项:
一旦执行throw new 异常类的构造方法;语句,该语句下面的代码都不在执行
throw new 异常类的构造方法下面不能有任何语句马,因为永远执行不到
*/
public class ExceptionDemo02 {
public static void main(String[] args) {
int[] arr = new int[3];
/* int i = method(arr, 2);
System.out.println(i); //0*/
int i = method(null, 1);
System.out.println(i);
int j = method(arr, 5);
System.out.println(j);
}
public static int method(int[] arr, int index) {
//如果传null
/*
当arr==null的时候,return -1 会产生歧异
1.定义method()方法的人认为如果arr为null,无法从数组中取元素,因此返回-1
2.使用method()方法的人认为如果arr为null,结果返回 -1 认为数组中1索引位置元素值为 -1
return 后面无论写任何值,都不能避免这个歧义
throw 后面抛出的异常类,只能是异常体系的一员
*/
if (arr == null) {
//return -1;
throw new NullPointerException("arr的值不能为null");
//throw new String("abc");
}
if (!(index > 0 && index <= arr.length - 1)) {//索引错误的范围
throw new ArrayIndexOutOfBoundsException(index + "这个索引超出数组索引范围");
//int i=3; //异常就停止执行代码,永远执行不到这句代码
}
return arr[index];
}
}
3.throws关键字异常声明 throws关键字 当方法中抛出异常对象,我们为了让调用者知晓这个方法可能又异常抛出 需要在方法上通过throws关键字声明异常类 格式: 修饰符 返回值类型 方法名(形参列表) throws 异常类名1,异常类名2,....{ }
import java.sql.SQLOutput;
/*
throws关键字
当方法中抛出异常对象,我们为了让调用者知晓这个方法可能又异常抛出
需要在方法上通过throws关键字声明异常类
格式:
修饰符 返回值类型 方法名(形参列表) throws 异常类名1,异常类名2,....{
}
*/
public class ExceptionDemo03 {
public static void main(String[] args) throws Exception{//main方法这里的throws异常声明是给jvm看的
//
/* int totalPrice = getTotalPrice(3, 20);
System.out.println(totalPrice);*/
/* int totalPrice2 = getTotalPrice(-2, 30);
System.out.println(totalPrice2);//-60*/
int totalPrice3 = getTotalPrice(2, -30);
System.out.println(totalPrice3);
}
/**文档注释
*
* @param price 单价
* @param amount 数量
* @return 返回总价
*/
public static int getTotalPrice(int price, int amount) throws Exception{//这个异常申明是给调用getPrice()方法的调用者看的
//当他看到这个异常声明就知道需要处理
if (price < 0) {
throw new Exception("价格不能为负值"+price);
}
if (amount < 0) {
throw new Exception("数量不能为负值" + amount);
}
return price * amount;
}
}
4.编译时异常与运行时异常 异常类(Exception)类: 运行时异常:RuntimeException类及 RuntimeException类的子类 编译时异常:非RuntimeException类及 非RuntimeException类的子类 运行时异常的特点: 运行时异常可处理(throw,throws,try....catch)可不处理 编译时异常如果代码中有异常(throw),那么需要处理(throws,try...catch)处理 什么时候用运行时异常? 如果程序中出现的问题无法再编译时期被检测,而需要在运行时期检测,那么我就需要使用运行时异常 例如:例如数组索引越界,数组在运行时期才会在堆内存开辟数组,此时才回去找索引,当索引超出边界时候才报错 什么时候用编译时异常? 如果程序中出现的问题可以在编译时期检测,那么我们可以考虑使用编译时异常 例如:价格和数量一旦有负值,我们知道计算总价肯定出问题 Father类
import java.io.IOException;
import java.util.zip.DataFormatException;
/*
编译时异常在注释中的使用规则:
1.如果父类中的方法声明的有异常,那么子类在重写该方法的时候,
可以不声明该异常或者声明该异常或者声明该异常的子类
2.如果父类中的方法声明多个异常,那么子类在重写该方法的时候,
可以声明父类异常的子集(包含空集)
{a,b} {a} {b} {a,b} 空集
3.如果没有声明异常,子类在重写该方法时也不能声明异常
*/
class Father {
public void method01() throws Exception {
}
public void method02() throws Exception {
}
public void method03() throws Exception {
}
public void method04()throws DataFormatException,IOException {
}
public void method05()throws DataFormatException,IOException {
}
public void method06()throws DataFormatException,IOException {
}
public void method07(){
}
}
class Son extends Father {
@Override
public void method01() {
}
@Override
public void method02() throws Exception {
}
@Override
public void method03() throws IOException {
}
@Override
public void method04()throws DataFormatException,IOException {
}
@Override
public void method05()throws DataFormatException {
}
@Override
public void method06() {
}
/* @Override
public void method07() throws Exception {
}*/
}
Son类
import java.io.IOException;
import java.util.zip.DataFormatException;
/*
编译时异常在注释中的使用规则:
1.如果父类中的方法声明的有异常,那么子类在重写该方法的时候,
可以不声明该异常或者声明该异常或者声明该异常的子类
2.如果父类中的方法声明多个异常,那么子类在重写该方法的时候,
可以声明父类异常的子集(包含空集)
{a,b} {a} {b} {a,b} 空集
3.如果没有声明异常,子类在重写该方法时也不能声明异常
*/
class Father {
public void method01() throws Exception {
}
public void method02() throws Exception {
}
public void method03() throws Exception {
}
public void method04()throws DataFormatException,IOException {
}
public void method05()throws DataFormatException,IOException {
}
public void method06()throws DataFormatException,IOException {
}
public void method07(){
}
}
class Son extends Father {
@Override
public void method01() {
}
@Override
public void method02() throws Exception {
}
@Override
public void method03() throws IOException {
}
@Override
public void method04()throws DataFormatException,IOException {
}
@Override
public void method05()throws DataFormatException {
}
@Override
public void method06() {
}
/* @Override
public void method07() throws Exception {
}*/
}
5.try...catch...finally a.try...catch处理单个异常 手动处理异常 我们可以通过throw关键字抛出一个异常对象 格式:throw new 异常类的构造方法 注意事项: 一旦执行throw new 异常类的构造方法;语句,该语句下面的代码都不在执行 throw new 异常类的构造方法下面不能有任何语句马,因为永远执行不到 b.try...catch处理多个异常 手动处理异常 格式: try{//检测可能出啊先异常的代码 //一般写可能出现异常的代码 }catch(异常类型 变量名){//捕获异常对象 //catch中异常类型定义为try中可能出现的异常类型 //处理异常的代码 }catch(异常类型2 变量名){ //不同的异常要找对应的catch处理,相当于对症下药 }....后面可以写多个catch块 c.finally代码块 第一种格式: try{ //第一种可能:try中的代码没有抛出异常,那么会去执行finally中的语句,程序继续向下执行 //第二种可能:try中的代码出现了异常,异常下面的代码不再执行(try中的),接着会去找对应的catch处理这个异常 执行catch中的语句,执行完catch中的语句,接着会去执行finally中的语句 finally语句执行完之后,程序继续向下执行 }catch(异常类型 变量名){ }....finally{ //finall跟在最后一个catch末尾 //无论try中是否抛出异常,finally中的语句都会执行 //我们一般把资源释放语句放在finally中,防止资源无法释放,例如:IO流关闭,数据连接关闭... } 第二种格式: try{ //第一种可能:try中的代码没有抛出异常,那么会去执行finally中的语句,程序继续向下执行 //第二种可能:try中的代码出现了异常,此时try下面的语句不再执行(try中),接着会去执行finally中的语句 执行完finally中的语句之后,JVM还去处理这个异常,采用默认处理方式,打印异常信息和异常追踪信息 最后停止程序 }finally{ //无论try中是否抛出异常,finally中的语句都会执行 } d.try...catch注意事项 try...catch注意事项: 1.如果多个catch中的异常类型没有父子关系,那么多个catch的顺序不影响最终结果 2.如果多个catch中的异常又父子类型,那么父类型的catch不能放在子类型的上面 因为无论子类型异常对象,还是父类型异常对象都会被父类型的catch捕获,那么在父类型catch下面的子类型catch将永远执行不到 解决方案: 将子类型catch放在父类型的catch上方
/*
第一种格式:
try{
//第一种可能:try中的代码没有抛出异常,那么会去执行finally中的语句,程序继续向下执行
//第二种可能:try中的代码出现了异常,异常下面的代码不再执行(try中的),接着会去找对应的catch处理这个异常
执行catch中的语句,执行完catch中的语句,接着会去执行finally中的语句
finally语句执行完之后,程序继续向下执行
}catch(异常类型 变量名){
}....finally{ //finall跟在最后一个catch末尾
//无论try中是否抛出异常,finally中的语句都会执行
//我们一般把资源释放语句放在finally中,防止资源无法释放,例如:IO流关闭,数据连接关闭...
}
第二种格式:
try{
//第一种可能:try中的代码没有抛出异常,那么会去执行finally中的语句,程序继续向下执行
//第二种可能:try中的代码出现了异常,此时try下面的语句不再执行(try中),接着会去执行finally中的语句
执行完finally中的语句之后,JVM还去处理这个异常,采用默认处理方式,打印异常信息和异常追踪信息
最后停止程序
}finally{
//无论try中是否抛出异常,finally中的语句都会执行
}
*/
public class ExceptionDemo06 {
public static void main(String[] args) throws Exception{//main方法这里的throws异常声明是给jvm看的
//method01();
try {
/* int totalPrice = getTotalPrice(3, 20);
System.out.println(totalPrice);*/
int totalPrice = getTotalPrice(-3, 20);
System.out.println(totalPrice);
}finally{
System.out.println("fially中的代码语句被执行");
}
System.out.println("程序执行结束");
}
/**文档注释
*
* @param price 单价
* @param amount 数量
* @return 返回总价
*/
public static int getTotalPrice(int price, int amount) throws Exception{
//当他看到这个异常声明就知道需要处理
if (price < 0) {
throw new Exception("价格不能为负值"+price);
}
return price * amount;
}
private static void method01() {
try {
/* int totalPrice = getTotalPrice(3, 20);
System.out.println(totalPrice);*/
int totalPrice = getTotalPrice(-3, 20);
System.out.println(totalPrice);
} catch (Exception e) {
System.out.println("捕获了Exception异常");
}finally{
System.out.println("fially中的代码语句被执行");
}
System.out.println("程序执行结束");
}
}
6.异常在编译时的使用规则 编译时异常在注释中的使用规则: 1.如果父类中的方法声明的有异常,那么子类在重写该方法的时候, 可以不声明该异常或者声明该异常或者声明该异常的子类 2.如果父类中的方法声明多个异常,那么子类在重写该方法的时候, 可以声明父类异常的子集(包含空集) {a,b} {a} {b} {a,b} 空集 3.如果没有声明异常,子类在重写该方法时也不能声明异常 7.异常体系的方法 Throwable中的方法:被所有的异常类继承,所有的异常对象都可以使用 String getMessage() 返回异常对象中封装的异常信息 void printStackTrace() 打印的时异常信息和异常追踪信息 8.自定义异常 将AgeException继承Exception类或者RuntimeException类就可以成为异常体系的一员 如果继承Exception代表这个自定义异常为编译时异常 如果继承RuntimeExceptio那么这个异常就是运行时异常 class 类名 extends Exception 或RuntimeException{ public 类名(){ super(); } public 类名(String message){ super(message); } }
自定义异常
/*
将AgeException继承Exception类或者RuntimeException类就可以成为异常体系的一员
如果继承Exception代表这个自定义异常为编译时异常
如果继承RuntimeExceptio那么这个异常就是运行时异常
*/
public class AgeException extends Exception {
public AgeException() {
}
public AgeException(String str) {
super(str);
}
}
Person类
public class Person {
private int age;
public Person(int age) throws AgeException{
if (age < 0) {
/*
当年龄<0的时候,我们考虑抛出一个异常对象,提示调用者
但是为了让这个异常对象见名知意,所以我们不抛出Exception
throw new 年龄异常();
*/
//throw new AgeException();
throw new AgeException("年龄不能为" + age);
}
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age)throws AgeException {
if (age < 0) {
throw new AgeException();
}
this.age = age;
}
}
测试模块
public class Demo01 {
public static void main(String[] args) throws AgeException{
Person p = new Person(-10);
p.setAge(12);
System.out.println(p.getAge());
}
}
运行结果