目录
①前言:
②常见的运行时异常
③常见的编译时异常
④异常的处理机制
⑤自定义异常
①前言:
1.什么是异常?
异常是程序在“编译”或者“执行”的过程中可能出现的问题,注意:语法错误不算在异常体系中。
比如: 数据索引越界异常,空指针异常,日期格式异常,等。
2.为什么要学习异常?
异常一旦出现,如果没有提前处理,程序就会退出JVM虚拟机而终止。
研究异常并且避免异常,然后提前处理异常,体现的是程序的安全,健壮性。
3.异常体系
Error: 系统级别的问题,JVM退出等,代码无法控制。
Exception: java.lang包下,称为异常类,它表示程序本身可以处理的问题。
RuntimeException及其子类: 运行时异常,编译阶段不会报错。(空指针异常,数组索引越界异常)
除RuntimeException之外的所有异常: 编译时异常,编译器必须处理的,否则程序不能通过编译。(日期格式化异常)
4.编译时异常和运行时异常
javac.exe 编译时异常,是在编译成class文件时必须要处理的异常,也称之为受检异常。
java.exe 运行时异常,在编译成class文件不需要处理,在运行字节码文件时可能出现的异常。
简单来说:
编译时异常,就是在编译时就出现的异常;
运行时异常,就是在运行时出现的异常。
②常见的运行时异常
1.运行时异常
直接继承自RuntimeException或者其子类,编译阶段不会报错,运行时可能出现的错误。
2.运行时异常示例:
①数据索引越界异常ArrayIndexOutOfBoundsException
②空指针异常NullPointerException 直接输出没问题,但调用空指针的变量的功能就会报错
③类型转换异常ClassCastException
④数学操作异常ArithmeticException
⑤数字转换异常NumberFormatException
运行时异常:
一般是程序员业务没考虑就好或者编译逻辑不严谨引起的程序错误。
3.代码演示:
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**异常 程序在编译或运行中出现错误(语法错误不算在异常体系中)
* Throwable
* Error 系统级别的错误
* Exception 程序级别的异常(RuntimeException 运行时异常 ) 编译时异常(受检异常)
*/
public class Exception_Demo1 {
public static void main(String[] args) throws ParseException {
//运行时异常
// //1.数据索引越界异常ArrayIndexOutOfBoundsException
// int[] arr = {10,21,34};
// System.out.println(arr[3]);//越界异常
// //2.空指针异常NullPointerException 直接输出没问题,但调用空指针的变量的功能就会报错
// String name = null;
// System.out.println(name);
// System.out.println(name.length());
// //3.类型转换异常ClassCastException
// Object o = 23;
// String s = (String) o;
// //4.数学操作异常ArithmeticException
// int c = 10/0;
// //5.数据转换异常NumberFormatException
// String number = "23 aa bb";
// Integer it = Integer.valueOf(number);
// System.out.println(it+1);
}
}
③常见的编译时异常
1.编译时异常
除RuntimeException之外的所有异常,编译阶段就报错,必须处理,否则代码不通过。
2.编译时异常的作用是什么?
担心程序员技术不行,在编译阶段就爆出一个错误,目的在于提醒不要出错;
3.代码演示:
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 编译时异常的解决方式:
* 1、抛出异常:只能抛出一个异常
* 抛出异常规范操作 直接抛出throws Exception{}
* 抛出异常并不好,如果异常最终抛出去给虚拟机会引起程序死亡
*2、 监视捕获异常格式 :捕获异常
* try{
* 监视可能出现异常的代码
* }catch(异常类型1 变量){
* //处理异常
* }
* 3、 前两者结合
*
* 运行时异常处理方式:
* 编译阶段不会报错,可以不抛,默认抛上去
*/
public class Exception_Demo1 {
public static void main(String[] args) throws ParseException {
//编译时异常
//简单日期格式化类
// String date = "2015-01-12 10:23:21";
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// //解析字符串成为日期对象
// Date d = sdf.parse(date);
// System.out.println(d);
passTime("2022-12-11 12:24:13");
}
public static void passTime(String date){
System.out.println("--------------------------------------");
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
} catch (Exception e) {
// e.printStackTrace();//打印异常栈信息
System.out.println("出现了解析时间异常");
}
try {
InputStream is = new FileInputStream("E:/meinv.jpg");
} catch (Exception ex) {
// ex.printStackTrace();
System.out.println("没有这个文件,不要骗我");
}
}
}
④异常的处理机制
1.编译时异常
编译时异常是编译阶段就出错的,所以必须处理,否则代码根本无法通过。
2.编译时异常的处理形式有三种:
①出现异常直接抛出去给调用者,调用者也继续抛出去。
②出现异常自己捕获处理,不麻烦别人;
③前两者结合,出现异常直接抛出去给调用者,调用者捕获处理。
3.异常处理方式之一:throws
throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理。
这种处理方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。
抛出异常格式:
规范做法:
4.异常处理方式之二:try...catch...
监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理。
这种方式,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行。
格式:
5.异常处理方式之三:前两者结合
方法直接将异常通过throws抛出去给调用者
调用者收到异常后直接捕获处理。
6.代码演示:
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
Exception 异常处理方式
*/
public class Exception_Test1 {
//异常处理方式之二:try...catch...
public static void main(String[] args) {
System.out.println("程序开始~~");
try {
passTime("2022-12-11 12:24:13");
System.out.println("程序操作成功~~");
} catch (Exception e) {
e.printStackTrace();
System.out.println("程序操作失败~~");
}
System.out.println("程序结束~~");
}
//异常处理方式之一:throws
public static void passTime(String date) throws Exception{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
InputStream is = new FileInputStream("E:/meinv.jpg");
}
}
7.异常处理的总结
在开发中按照规范来说第三种方式是最好的:底层的异常抛出去给最外层,最外层集中捕获处理。
实际应用中,只要代码能够编译通过,并且功能能完成,那么每一种异常处理方式似乎也都是可以的。
8.案例:异常处理使代码更稳健的案例
需求:
键盘录入一个合理的价格为止(必须是数值,值必须大于0)。
分析:
定义一个死循环,让用户不断的输入价格;
import java.util.Scanner;
/** 案例
* 键盘录入一个合理的价格位置
* 定义一个死循环,不断输入价格
*/
public class Exception_Test2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
try {
System.out.println("请您输入一个合理的价格");
String priceStr = sc.nextLine();//接一行数据
//转换成double类型的价格 判断价格大于0
double price = Double.valueOf(priceStr);
if (price >0) {
System.out.println("定价:"+price);
break;
}else {
System.out.println("价格必须是正数~~");
}
} catch (NumberFormatException e) {
System.out.println("用户输入的数据无效,请您输入合法的数据");
}
}
System.out.println("----------------------------------");
//自定义异常
try {
checkAge(34);
} catch (Exception_Demo2 e) {
throw new RuntimeException(e);
}
}
public static void checkAge(int age) throws Exception_Demo2 {
if (age<0 || age>200){
//抛出去一个异常对象给调用者
//throw:在方法内部直接创建一个异常对象,并由此点抛出
//throws:用在方法上面声明上的,抛出方法内部的异常
throw new Exception_Demo2(age+"IS Illeagal!");
}else {
System.out.println("年龄合法,推荐商品给其购买");
}
}
}
⑤自定义异常
1.自定义异常的必要?
java无法为这个世界上全部问题提供异常类。
如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了。
2.自定义异常的好处?
可以使用异常的机制管理业务问题,如提醒程序员注意;
同时一旦出现bug,可以用异常的形式清晰的指出出错的地方。
3.自定义异常的分类
(1)自定义编译时异常
①定义一个异常继承Exception;
②重写构造器;
③在出现异常的地方用throw new自定义对象抛出。
作用:
编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理。
代码演示:
/**自定义异常
* 1、自定义编译异常
* 1。继承Exception
* 2.重写构造器
* 3.在出现异常的地方,用throw new自定义对象抛出
* 作用:编译时异常编译时就报错,提醒更加强烈,一定需要处理
*
* 2、自定义运行异常
* 1。继承RuntimeException
* 2.重写构造器
* 3.在出现异常的地方,用throw new自定义对象抛出
* 作用:运行时才出现
*
*
* throw:在方法内部直接创建一个异常对象,并由此点抛出
* throws:用在方法上面声明上的,抛出方法内部的异常
*/
public class Exception_Demo2 extends Exception {
public static void main(String[] args) {
try {
checkAge(-34);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void checkAge(int age)throws Exception{
if (age < 0 || age > 200){
/*抛出一个异常对象给调用者
throw:在方法内部直接创建一个异常对象,并从此点抛出。
throws:用在方法申明上的,抛出方法内部的异常。
*/
throw new Exception(age+"is illeagal");
}else {
System.out.println("年龄合法:推荐商品给其购买~~~");
}
}
}
(2)自定义运行时异常
①定义一个异常类继承RuntimeException;
②重写构造器;
③在出现异常的地方用throw new 自定义对象抛出。
作用:
提醒不强烈,编译阶段不报错,运行时才可能出现。