目录
Exception: java.lang包下,称为异常类,它表示程序本身可以处理的问题
异常
异常是程序在“编译”或者“执行”的过程中可能出现的问题,注意:语法错误不算在异常体系中。
比如:数组索引越界、空指针异常、数字转换异常、日期格式化异常、类型转换异常、算数异常(数学异常)
异常体系
Error:系统级别问题、JVM退出等,代码无法控制。
Exception: java.lang包下,称为异常类,它表示程序本身可以处理的问题
RuntimeException及其子类:运行时异常(运行时出现的异常),编译阶段不会报错。(空指针异常,数组索引越界异常)
除RuntimeException之外所有的异常:编译时异常(编译时出现的异常),编译期必须处理的,否则程序不能通过编译。(日期格式化异常)。
常见的运行时异常
运行时异常:直接继承自RuntimeException或者其子类,编译阶段不会报错,运行时可能出现的错误。
数组索引越界异常:ArraylndexoutOfBoundsException
空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。
数学操作异常:ArithmeticException
类型转换异常:ClassCastException
数字转换异常:NumberFormatException
数组索引越界异常:ArraylndexoutOfBoundsException
//数组索引越界异常:ArraylndexoutOfBoundsException
public static void main(String[] args) {
int arr[] = {10, 20, 30};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
}
}
注意:把后报的错误放到上面,先进的在下面,后进的在上面,后进先出是栈。因此是异常栈信息。
空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。
//空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。
public class Cjiande {
public static void main(String[] args) {
System.out.println("开始");
//空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。
String name=null;
System.out.println(name);//没问题
System.out.println(name.length());
}
}
数学操作异常:ArithmeticException
//数学操作异常:ArithmeticException
int num1 = 10/0;
类型转换异常:ClassCastException
//类型转换异常
Object O=23;
String a= (String) O;
数字转换异常:NumberFormatException
String s="122";
Integer integer=Integer.valueOf(s);
System.out.println(integer);//正常输出
System.out.println("-----------------------");
//数字转换异常:NumberFormatException
String s="122ass";
Integer integer=Integer.valueOf(s);//运行出错,程序终止
System.out.println(integer);
编译时异常
不是RuntimeException或者其子类的异常,编译阶就报错,必须处理,否则代码不通过。
package com.jr.morning.test;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
public static void main(String[] args) {
String date="2022-07-29 11:18:25";
//创建一个简单日期格式类,解析字符串时间成为日期对象
SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式一定要与上面的格式相同,否则解析失败
Date d=sim.parse(date);//报错,(查看下图
System.out.println(d);
}
}
下图就是编译时异常
解决方法:alt+Enter,选择第一个第二个都行。
异常的默认处理流程(不好)
①默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException。
②异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机。
③虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据。
④直接从当前执行的异常点干掉当前程序。
⑤后续代码没有机会执行了,因为程序已经死亡。
异常的处理机制
编译时异常是编译阶段就出错的,所以必须处理,否则代码根本无法通过
编译时异常的处理形式有三种
1.出现异常直接抛出去给调用者,调用者也继续抛出去。(出现异常,不管,往上抛,都不管,层层往上抛<默认处理方式>)
2.自己捕获处理,不麻烦别人。
3.前两者结合,出现异常直接抛出去给调用者,调用者捕获处理。
异常处理方式1—— throws
throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理。
这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。
抛出异常格式:
方法 throws 异常1,异常2,异常3..{
}
案例解析:
定义一个parseTime类,现在parse是报错的,要给它往外抛。
package com.jr.morning.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
public static void main(String[] args) throws ParseException {
System.out.println("开始");
parseTime("2022-07-28 11:52:20");
System.out.println("结束");
// String date="2022-07-29 11:18:25";
// //创建一个简单日期格式类,解析字符串时间成为日期对象
// SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式一定要与上面的格式相同,否则解析失败
// Date d=sim.parse(date);
// System.out.println(d);
}
public static void parseTime(String date){
SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d=sim.parse(date);//报错!!
System.out.println(d);
}
}
加throws ParseException
public static void parseTime(String date) throws ParseException {
SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d=sim.parse(date);
System.out.println(d);
}
}
规范做法:
方法 throws Exception{
}
异常处理方式2——try...catch...
格式: 建议格式:
快速创建try...catch...的快捷键:全选上,CTRL+alt+T
package com.jr.morning.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("开始");
parseTime("2022-07-28 11:52:20");
System.out.println("结束");
// String date="2022-07-29 11:18:25";
// //创建一个简单日期格式类,解析字符串时间成为日期对象
// SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式一定要与上面的格式相同,否则解析失败
// Date d=sim.parse(date);
// System.out.println(d);
}
public static void parseTime(String date) {
try {
SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d=sim.parse(date);
System.out.println(d);
} catch (ParseException e) {
//解析出现问题
System.out.println("出现了解析时间异常");
}
}
}
异常处理方式3——前两者结合
方法直接将异通过throws抛出去给调用者
调用者收到异常后直接捕获处理。
package com.jr.morning.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("开始");
try {
parseTime("2022-07-28 11:52:20");
System.out.println("功能操作成功");
} catch (ParseException e) {
e.printStackTrace();
System.out.println("失败");
}
System.out.println("结束");
// String date="2022-07-29 11:18:25";
// //创建一个简单日期格式类,解析字符串时间成为日期对象
// SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式一定要与上面的格式相同,否则解析失败
// Date d=sim.parse(date);
// System.out.println(d);
}
public static void parseTime(String date) throws ParseException {
SimpleDateFormat sim=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d=sim.parse(date);
System.out.println(d);
}
}
运行时异常处理机制
运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以。
按照规范建议还是处理:建议在最外层调用处集中捕获处理即可。
package com.jr.morning.test;
/*运行处理机制*/
public class ExceptRunTime {
public static void main(String[] args) {
System.out.println("开始");
try {
chu(1, 0);//③
} catch (Exception e) {
e.printStackTrace();//④
}
System.out.println("结束");
}
public static void chu(int a, int b) {// ②
int c = a / b;①
System.out.println(c);
}
}
先从①抛到②,再从②抛到③,然后由④去打印出来的。
异常处理代码更稳健的案例
需求
键盘录入一个合理的分数为止(必须是数值,值必须大于0)。
分析
定义一个死循环,让管理员不断输入分数直到正确位置
package com.jr.morning.test;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(true){
System.out.println("请输入合法分数:");
String score=scanner.nextLine();
//转换成double类型的分数
double score1=Double.valueOf(score);
//判断分数是否大于0
if(score1>0){
System.out.println("分数为:"+score1);
break;
}else {
System.out.println("分数必须为正数");
}
}
}
}
我们发现可以运行,但是可能存在乱输入的情况,比如说输入一个"43.2.6.5aaa",转不了double
程序挂了...不稳健。因此,可以将判断的代码放到try..catch..里面。只要catch拦截到了异常,说明用户在乱输入,不然不能拦截到异常,一旦拦截到乱输入的数据后,程序就不会死亡 ,这样可以让用户循环再继续输入数据。
package com.jr.morning.test;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(true){
try {
System.out.println("请输入合法分数:");
String score=scanner.nextLine();
//转换成double类型的分数
double score1=Double.valueOf(score);
//判断分数是否大于0
if(score1>0){
System.out.println("分数为:"+score1);
break;
}else {
System.out.println("分数必须为正数");
}
} catch (Exception e) {
System.out.println("输入有误!请重新输入...");
}
}
}
}
自定义异常
自定义编译时异常
定义一个异常类继承Exception
重写构造器。
在出现异常的地方用throw new自定义对象抛出作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!
案例 需求:认为年龄小于18,大于60岁就是异常。
首先定义一个自定义异常
package com.jr.morning.test;
/*把年龄非法做成一个自定义编译时异常
* 1.继承Exception
* 2.重写构造器*/
public class AgeException extends Exception{
public AgeException() {
}
public AgeException(String message) {//可以把原因写进去
super(message);
}
}
package com.jr.morning.test;
import com.jr.afternoon.AgeException;
/*需求:认为年龄小于18,大于60岁就是异常 */
public class ExceptDemo {
public static void main(String[] args) {
try {
checkAge(34);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void checkAge(int age) throws AgeException {
if (age<18||age>60){
//抛出去一个异常给调用者
//throw:在方法内部直接创建一个异常对象,并从此点抛出
//throws:用在方法申明上面,抛出方法内部的异常
throw new AgeException(age+" 是非法的");
}else {
System.out.println("年龄合法");
}
}
}
自定义运行时异常
定义一个异常类继承RuntimeException.重写构造器。
在出现异常的地方用throw new自定义对象抛出!
作用:提醒不强烈,编译阶段不报错!以运行时才可能出现!!
Throw和throws的区别
1.位置不同
throw:方法的内部
throws:方法的声明处
2.内容不同
throw new 异常();
throws+异常类型的对象(可以有多个类型 用,连接)
3.作用不同
throw:异常的源头,制造异常
throws:声明异常,告诉方法的调用者,这个方法可能会出现的异常,然后调用者对这些异常进行处理
finally关键字
1.finally是可选的
2.finally 中声明的是一定会被执行的代码,即使catch中又出现异常,try中有return语句,catch中可能也会有return语句。
3.一般finally中的代码都是用来释放资源
案例:
package com.jr.morning.test;
import static com.jr.morning.test.ExceptRunTime.chu;
public class Finally_Test {
public static void main(String[] args) {
System.out.println("开始");
try {
chu(1, 1);
} catch (Exception e) {
//e.printStackTrace();
int[]arr=new int[5];
System.out.println(arr[5]);
}finally {
System.out.println("我是美女");
}
}
public static void chu(int a, int b) {
int c = a / b;
System.out.println(c);
}
}
总结
今天学习了异常,包括运行时异常、编译时异常。以及两种异常的处理方式、自定义异常、finally关键字。总体来说掌握得还不错,后续还要多练习项目加深巩固。
今日分享
竹深树密虫鸣处,时有微凉不是风。——杨万里《夏夜追凉》