什么是异常?
异常:异常就是代表程序出现的问题
误区:不是让我们以后不出现异常,而是程序出了异常之后该如何处理
Error
代表系统级别的错误(属于原重问题)
系统一旦出现问题,sun公司会把这些错误封装成Error对象。Error是给sun公司自己用的,不是给我们程序员用的。因此我们开发人员不用管它。
Excetion
代表程序可能出现问题
我们通常会用Exception以及它的子类类封装程序出现的问题。
运行时异常(RuntimeException)
RuntimeException及其子类,编译阶段不会出现异常提醒。运行时出现异常(数组越界异常)
package 异常;
public class 运行时异常 {
public static void main(String[] args) {
/*运行时异常*/
int[] arr = {0,1,2};
System.out.println(arr[10]);
/*Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 3
at 异常.运行时异常.main(运行时异常.java:7)*/
}
}
编译时异常
编译阶段就会出现的异常提醒(日期解析异常)
package 异常;
import javax.xml.crypto.Data;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class 编译时异常 {
public static void main(String[] args) throws ParseException {
/*编译时异常
* 在编译时期必须手动处理,否则代码报错*/
String time = "2021年2月1日0";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Data data = (Data) sdf.parse(time);
System.out.println(data);
}
}
小结:
- 异常是什么?
- 程序中可能出现的问题
- 异常体系的最上层父类是谁?异常分为几类?
- 父类:Exception
- 异常分为两类:编译时异常、运行时异常
- 编译时异常和运行时异常的区别:
- 编译时异常:没有继承RuntimeException的异常,直接继承于Exception。编译阶段就会有错误提示
- 运行时异常:RuntimeException本身和子类。编译时没有错误提示,运行时出现错误;
运行时异常和编译时异常
编译时异常:编译阶段就要处理的异常(如:日期解析异常)
运行时异常:RuntimeException及其子类,编译阶段不需要处理。代码运行时出现的异常(如:数组越界异常)
扩展:为什么不将异常归并为一个类?
- 编译阶段:Java不会运行代码,自会检查语法是否错误,或做出一些性能优化
- 运行遗产:代码出错导致程序出现的问题
编译时期异常的目的:提醒程序员检查本地信息!
运行时异常和编译时异常的区别
- 编译时异常:除了RuntimeException和它的子类,其他的都是编译时异常。编译阶段需要进行处理,作用在于提醒程序员。
- 运行时异常:RuntimeException本身和所有的子类都是运行时异常。【编译阶段不报错,程序运行时报错,是程序运行时出现的。一般是由于参数传递错误带来的问题】
异常的作用
- 作用1:异常是用来查询bug的关键参考信息
- 作用2:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
异常是用来查询bug的关键参考信息
package 异常;
public class Student1 {
private String name;
private int age;
public Student1() {
}
public Student1(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student1{name = " + name + ", age = " + age + "}";
}
}
package 异常;
public class 异常的作用1 {
public static void main(String[] args) {
/*作用1:异常是用来查询bug的关键参考信息
作用2:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
*/
Student1[] arr = new Student1[3];
String name = arr[0].getName();
System.out.println(name);
/**Exception in thread "main" java.lang.NullPointerException: Cannot invoke "异常.Student1.getName()" because "arr[0]" is null
at 异常.异常的作用.main(异常的作用.java:10)
空指针异常*/
}
}
package 异常;
public class Student2 {
private String name;
private int age;
public Student2() {
}
public Student2(String str) {
String[] arr = str.split("-");
this.name = arr[0];
this.age = Integer.parseInt(arr[1]);
}
public Student2(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student2{name = " + name + ", age = " + age + "}";
}
}
package 异常;
public class 异常的作用1_2 {
public static void main(String[] args) {
/*作用1:异常是用来查询bug的关键参考信息
作用2:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
*/
Student2 stu = new Student2("张三,23");
System.out.println(stu);
}
}
异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
package 异常;
public class Student1 {
private String name;
private int age;
public Student1() {
}
public Student1(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
if (age < 18 || age > 40){
throw new RuntimeException();
} else
this.age = age;
}
public String toString() {
return "Student1{name = " + name + ", age = " + age + "}";
}
}
package 异常;
public class 异常的作用2_1 {
public static void main(String[] args) {
/*
作用1:异常是用来查询bug的关键参考信息
作用2:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
*/
/*1、创建学生对象*/
Student1 s1 = new Student1();
//年龄:(同学)18-40岁
s1.setAge(50);
/**
Exception in thread "main" java.lang.RuntimeException
at 异常.Student1.setAge(Student1.java:45)
at 异常.异常的作用2_1.main(异常的作用2_1.java:12)*/
}
}
异常的处理方式
- jvm默认处理
- 自己处理
- 抛出处理
jvm默认处理方式
- 把异常的名称,异常原因及异常的位置等信息输出在控制台
- 程序停止执行,下面代码不会再执行
package 异常.异常的处理;
public class JVM默认处理 {
public static void main(String[] args) {
/*JVM默认处理异常的方式
* 1、把异常的名称,异常原因及异常的位置等信息输出在控制台
2、程序停止执行,下面代码不会再执行*/
System.out.println("aaa");
System.out.println("dd");
System.out.println(1/0);
System.out.println("vv");
System.out.println("fdd");
}
}
aaa
dd
Exception in thread "main" java.lang.ArithmeticException: / by zero
at 异常.异常的处理.JVM默认处理.main(JVM默认处理.java:10)
自己处理(捕获异常)
目的:当代码出现异常时,程序可以继续执行。
格式:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
package 异常.异常的处理;
public class 自己处理 {
public static void main(String[] args) {
/*格式:
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}*/
int[] arr = {1,2,3,4,5};
try {
System.out.println(arr[10]);
} catch (RuntimeException rs){
System.out.println(rs);
}
System.out.println("执行了");
}
}
java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 5
执行了
灵魂四问
- 如果try中没有遇到问题,怎么执行?
- 执行try中的全部代码
- 不执行catch中的代码
package 异常.异常的处理;
public class 自己处理灵魂四问 {
public static void main(String[] args) {
/* 如果try中没有遇到问题,怎么执行?
如果try中可能会遇到多个问题,怎么执行?
如果try中遇到的问题没有被捕获,怎么执行?
如果try中遇到了问题,那么try下面的其他代码还会执行吗?*/
int[] arr = {1,2,3,4,5,6} ;
try {
System.out.println(arr[0]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("索引越界");
}
System.out.println("判断是否执行");
}
}
1
判断是否执行
- 如果try中可能会遇到多个问题,怎么执行?
- try中遇到错误程序代码就跳转catch进行匹配
- 当遇到多个异常时,可以写多个catch进行捕获
- 当我们捕获多个异常时,如果异常中存在父子关系,父类写最后
package 异常.异常的处理;
public class 灵魂二问 {
public static void main(String[] args) {
/*
如果try中可能会遇到多个问题,怎么执行?
*/
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
System.out.println(2/0);
} catch (ArrayIndexOutOfBoundsException e){
System.out.println("索引越界");
} catch (ArithmeticException e){
System.out.println("除数不能为0");
}
System.out.println("判断是否执行");
}
}
索引越界
判断是否执行
- 如果try中遇到的问题没有被捕获,怎么执行?
- 程序中断,try相当于没写,代码交给虚拟机处理
package 异常.异常的处理;
public class 灵魂三问 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);//ArrayIndexOutOfBoundsException
}catch (NullPointerException e){
System.out.println("空指针异常");
}
System.out.println("检查是否执行");
}
}
- 如果try中遇到了问题,那么try下面的其他代码还会执行吗?
- 不会!
- 代码直接跳转到catch中进行匹配
- catch中没有与之匹配将交给虚拟机
package 异常.异常的处理;
public class 灵魂四问 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);//ArrayIndexOutOfBoundsException
System.out.println("检查是否执行");
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("空指针异常");
}
}
}
空指针异常
Throwable的成员方法
getMessage : 返回此throwable的详细消息字符串
package 异常.异常的处理.Throwable;
public class getMessage {
public static void main(String[] args) {
/*getMessage : 返回此throwable的详细消息字符串*/
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("检查是否执行");
}
}
Index 10 out of bounds for length 6
检查是否执行
toString : 返回可抛出的简短描述
package 异常.异常的处理.Throwable;
public class toString {
public static void main(String[] args) {
/*toString : 返回可抛出的简短描述*/
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
} catch (Exception e) {
System.out.println(e.toString());
}
System.out.println("检查是否执行");
}
}
java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 6
printStackTrace:把异常的信息输出在控制台
package 异常.异常的处理.Throwable;
public class printStackTrace {
public static void main(String[] args) {
/*toString : 返回可抛出的简短描述*/
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("检查是否执行");
}
}
java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 6
at 异常.异常的处理.Throwable.toString.main(toString.java:8)
检查是否执行
抛出处理
- throws :【编译时异常:必须写,运行时异常:可以不写】
- 写在方法定义处,表示声明一个异常
- 告诉调用者,使用本方法可能会有那些异常
- throw:
- 写在方法内,结束方法。
- 手动抛出异常对象,交给调用者
- 方法中下面的代码不再执行
throw:写在方法内
package 异常.异常的处理;
public class Throw {
public static void main(String[] args) {
/* throw:
写在方法内,结束方法。
手动抛出异常对象,交给调用者
方法中下面的代码不再执行
*/
//需求:定义一个方法求数组的最大值
int[] arr = null;
System.out.println(getMax(arr));
//方法中下面的代码不再执行
System.out.println("检查是否执行");
}
public static int getMax(int[] arr){
if(arr == null || arr.length == 0 ){
//手动抛出异常对象,交给调用者
throw new NullPointerException();
}
int max = arr[0];
for (int a : arr){
if(a > max){
max = a;
}
}
return max;
}
}
Exception in thread "main" java.lang.NullPointerException
at 异常.异常的处理.Throw.getMax(Throw.java:20)
at 异常.异常的处理.Throw.main(Throw.java:12)
throws :【编译时异常:必须写,运行时异常:可以不写】
package 异常.异常的处理;
public class Throws {
public static void main(String[] args) {
/* throws :【编译时异常:必须写,运行时异常:可以不写】
写在方法定义处,表示声明一个异常
告诉调用者,使用本方法可能会有那些异常
*/
//需求:定义一个方法求数组的最大值
int[] arr = null;
try {
System.out.println(getMax(arr));
} catch (NullPointerException e) {
System.out.println("null");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界");
}
//方法中下面的代码不再执行
System.out.println("检查是否执行");
}
public static int getMax(int[] arr) throws NullPointerException,ArrayIndexOutOfBoundsException{
int max = arr[0];
for (int a : arr){
if(a > max){
max = a;
}
}
return max;
}
}
null
检查是否执行
总结:
- 虚拟机默认处理异常的方式
- 把异常的信息以红色字体打印在控制台,并结束程序
- 捕获:try...catch
- 一般用在调用出,让代码继续往下运行
- 抛出:throw、throws
- 在方法中出现异常,方法就没有继续运行的意义,采取抛出处理
- 让该方法结束运行并告诉调用者出现的问题
综合练习
无异常处理:
package 异常;
public class girlfriend {
private String name;
private int age;
public girlfriend() {
}
public girlfriend(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "girlfriend{name = " + name + ", age = " + age + "}";
}
}
package 异常;
import java.util.Scanner;
public class 综合练习 {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建女朋友的对象
girlfriend gf = new girlfriend();
System.out.println("请输入名字");
//接收名字
String name = sc.nextLine();
gf.setName(name);
//接受年龄
System.out.println("输入年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
gf.setAge(age);
//打印信息
System.out.println(gf);
}
}
请输入名字
sdgf
输入年龄
sdf
Exception in thread "main" java.lang.NumberFormatException: For input string: "sdf"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:665)
at java.base/java.lang.Integer.parseInt(Integer.java:781)
at 异常.综合练习.main(综合练习.java:18)
Process finished with exit code 1
增加异常处理:
package 异常;
public class girlfriend {
private String name;
private int age;
public girlfriend() {
}
public girlfriend(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
int length = name.length();
if (length < 3 || length > 10){
throw new RuntimeException();
}
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
if(age < 18 || age > 40){
throw new RuntimeException();
}
this.age = age;
}
public String toString() {
return "girlfriend{name = " + name + ", age = " + age + "}";
}
}
package 异常;
import java.util.Scanner;
public class 综合练习 {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建女朋友的对象
girlfriend gf = new girlfriend();
while (true) {
try {
System.out.println("请输入名字");
//接收名字
String name = sc.nextLine();
gf.setName(name);
//接受年龄
System.out.println("输入年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
gf.setAge(age);
break;
} catch (NumberFormatException e) {
System.out.println("年龄格式错误");
continue;
} catch (RuntimeException e){
System.out.println("姓名长度 或 年龄范围有误");
}
}
//打印信息
System.out.println(gf);
}
}
自定义异常
- 定义异常类
- 写继承关系
- 空参构造
- 带参构造
定义异常类
- 名字错误异常类
- 年龄错误异常类
名字错误异常类
package 异常.自定义异常;
public class NameFormatException extends RuntimeException {
//取名技巧
//NameFormat : 当前异常的名字,表示姓名格式化问题
//Exception : 表示当前类为异常类
//运行时 : RuntineEException 核心:表示参数错误导致的问题
//编译时 : Exception 核心:提醒程序员检查本地信息
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
年龄错误异常类
package 异常.自定义异常;
public class AgeOutOfBoundsException extends RuntimeException{
public AgeOutOfBoundsException() {
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
综合练习修改
package 异常.自定义异常;
public class girlfriend {
private String name;
private int age;
public girlfriend() {
}
public girlfriend(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
int length = name.length();
if (length < 3 || length > 10){
throw new NameFormatException(name + "格式有误,length < 3 || length > 10");}
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
if(age < 18 || age > 40){
throw new AgeOutOfBoundsException(age + "不在范围内");
}
this.age = age;
}
public String toString() {
return "girlfriend{name = " + name + ", age = " + age + "}";
}
}
package 异常.自定义异常;
import 异常.自定义异常.girlfriend;
import java.util.Scanner;
public class text {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建女朋友的对象
girlfriend gf = new girlfriend();
while (true) {
try {
System.out.println("请输入名字");
//接收名字
String name = sc.nextLine();
gf.setName(name);
//接受年龄
System.out.println("输入年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
gf.setAge(age);
break;
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (NameFormatException e){
e.printStackTrace();
} catch (AgeOutOfBoundsException e){
e.printStackTrace();
}
}
//打印信息
System.out.println(gf);
}
}