1. 异常的概念和体系
2.异常的分类
package Part2.Day_20.demo01;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class demo01exception {
public static void main(String[] args) {
/*
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = sdf.parse("1999-09-09");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(date);
*/
int[] arr ={1,2,3};
try {
//可能会出现异常的代码
System.out.println();
}catch (Exception e){
//异常的处理逻辑
System.out.println(e);
}
System.out.println("后续代码");
//int arr =new int[1024*1024*1024];
//OutOfMemoryError:Java heap space
//内存溢出的错误,超出JVM分配的内存,必须修改代码解决
}
}
3.抛出异常的过程及解析
4. throw关键字
package Part2.Day_20.demo01;
/*
throw关键字
作用:
可以使用throw,在指定的方法中抛出指定的异常
使用格式:
throw new xxxException("异常产生的原因");
注意:
1.throw关键字必须写在方法的内部
2.throw关键字后边new的对象必须是Exception或者是Exception的子类对象
3.throw关键字抛出指定的异常对象,我们就必须处理这个异常对象
throw关键字后边创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,
默认交给JVM处理(打印异常对象,中断程序)
throw关键字后边创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try catch
*/
public class demo03throw {
public static void main(String[] args) {
int[] arr= null;
int e = getelement(arr,0);
}
/*
工作中,首先必须对方法传递过来的参数进行合法性校验
如果参数不合法,必须使用抛出异常的方式,告知方法的调用者,传递的参数有问题
*/
public static int getelement(int[] arr, int index){
/*
我们可以对传递过来的参数数组,进行合法性校验
如果数组arr的值是null
那么我们就抛出空指针异常,告知方法的调用者“传递的数组的值是null”
注意:
NullPointerException是一个运行期异常,我们不用处理,默认交给JVM处理
ArrayIndexOutOfBoundsException是一个运行期异常,我们不用处理,默认交给JVM处理
*/
if (arr == null){
throw new NullPointerException("传递的数组的值是空");
}
/*
我们可以对传递过来的参数index进行合法性效验
如果Index的范围不在数组的索引范围内
那么我们就抛出数组索引越界异常,告知方法的调用者传递的索引超出了数组的使用范围
*/
if (index<0||index>arr.length-1){
throw new ArrayIndexOutOfBoundsException("数组的索引越界了");
}
int ele = arr[index];
return ele;
}
}
Exception in thread "main" java.lang.NullPointerException: 传递的数组的值是空
at Part2.Day_20.demo01.demo03throw.getelement(demo03throw.java:32)
at Part2.Day_20.demo01.demo03throw.main(demo03throw.java:19)
package Part2.Day_20.demo01;
import java.util.Objects;
/*
Objects类中的静态方法
*/
public class demo04Objects {
public static void main(String[] args) {
method(null);
}
public static void method(Object obj){
if (obj==null){
throw new NullPointerException("传递的对象是空");
}
//判断空指针的简化方法,直接调用Objects里写好的
//Objects.requireNonNull(obj);
Objects.requireNonNull(obj,"传递的对象的值是null");
}
}
5.声明异常throws
throws
package Part2.Day_20.demo01;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
throws关键字:异常处理的第一种方式,交给别人处理
作用:
当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象
可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终给JVM,中断处理
使用格式:在方法声明时使用
修饰符 返回值类型 方法名(参数列表) throws AAAExceptions, BBBException...{
throw new AAAException("产生原因");
throw new BBBException("产生原因");
}
注意:
1.throw关键字必须写在方法声明处
2.throw关键字后边声明的异常必须是Exception或者是Exception的子类
3.方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常
如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
4.调用了一个声明抛出异常的方法,我们就必须的处理声明的异常
要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM
要么try catch自己处理异常
*/
public class demo05throws {
/*
FileNotFoundException extends IOException extends Exception
如果抛出的多个异常对象有子父类的话,那么直接声明父类即可
IOException extends Exception
*/
/*
static void main(String[] args) throws FileNotFoundException,IOException {
*/
static void main(String[] args) throws IOException {
readFile("c::\\a.txt");
/*
如果是抛出throw,给JVM后将不会处理
如果是try catch,可以自己处理异常后继续执行
*/
System.out.println("后续代码");
}
/*
定义一个方法,对传递的文件路径进行合法性的判断
如果路径不是c::\\a.txt 那么我们就抛出文件找不到异常对象,告知方法调用者
注意:
FileNotFoundException是编译异常,抛出了编译异常,就必须处理这个异常
可以使用throws继续声明抛出FileNotFoundException这个异常对象让方法的调用者处理
*/
public static void readFile(String fileName) throws FileNotFoundException,IOException{
if (!fileName.equals("c::\\a.txt")){
throw new FileNotFoundException("传递的文件不是c::\\a.txt");
}
if (!fileName.endsWith(".txt")){
throw new IOException("文件的后缀名不对");
}
}
}
try catch
package Part2.Day_20.demo01;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
try...catch:异常处理的第二种方式,自己处理异常
格式:
try{
可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑
}
注意:
1.try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些对象
2.如果try中产生了异常,那么就会执行catch中的异常处理逻辑,继续执行之后的代码
3.如果try中没有产生异常,那么就不会执行catch中的异常处理逻辑,直接继续执行之后的代码
*/
public class demo01trycatch {
public static void main(String[] args) {
try {
readFile("d:\\a.txt");
} catch (IOException e) { //try中抛出什么异常对象,catch就定义什么异常变量用来接收异常对象
System.out.println("catch - 传递的文件后缀不是.txt");
System.out.println(e.getMessage()); //传递的文件不是c::\a.txt
System.out.println(e.toString()); //java.io.FileNotFoundException: 传递的文件不是c::\a.txt
System.out.println(e);//和调用toString打印的一样 //java.io.FileNotFoundException: 传递的文件不是c::\a.txt
e.printStackTrace();
/*
Throwable类中定义了3个异常处理的方法
String getMessage() 返回此throwable的简短描述
String toString() 返回此throwable 的详细消息字符串
void printStackTrace() JVM打印异常对象,默认此方法,打印的异常信息是最全面的
*/
}
System.out.println("后续代码");
}
public static void readFile(String fileName) throws IOException {
if (!fileName.equals("c::\\a.txt")){
throw new FileNotFoundException("传递的文件不是c::\\a.txt");
}
}
}
6.异常的注意事项:
多个异常使用捕获如何处理?
(1)多个异常分别处理
(2)多个异常,一次捕获,多次处理
一个try多个catch的注意事项:
catch里面定义的异常变量,如果有子父类关系,那么子类的一次变量必须写在上边,否则就报错
(3)多个异常一次捕获一次处理
// 运行时异常被抛出可以不处理,不捕获也不抛出
默认给虚拟机处理,终止程序,什么时候不抛出运行时异常了,再来继续执行程序
7. 异常注意事项,finally有return语句
package Part2.Day_20.demo02;
/*
如果fnially有return语句,永远返回finally中的结果,避免该情况
*/
public class demo02Exception {
public static void main(String[] args) {
int a =getA();
System.out.println(a);
}
public static int getA(){
int a =10;
try {
return a;
}catch (Exception e){
System.out.println(e);
}
finally {
//一定会执行的代码
a = 100;
return a;
}
}
}
父类异常是什么样,子类异常就什么样。
8.自定义异常类:
package Part2.Day_20.demo02;
/*
自定义异常类:
java提供的异常类,不够我们使用,需要自己定义异常类
格式:
public class XXXException extends Exception | RuntimeException{
空参数构造方法
带异常信息的构造方法
}
注意:
1.自定义异常类一般以Exception结尾,说明该类是一个异常类
2.自定义异常类必须的继承Exception或者RuntimeException
继承类Exception那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理,要么throw,要么try catch
继承RuntimeException:那么自定义的异常类就是一个运行期异常,给JVM中断处理
*/
public class RegisterException extends Exception{
public RegisterException(){
super();
}
//查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类处理此信息
public RegisterException(String message){
super(message);
}
}
package Part2.Day_20.demo02;
import java.util.Scanner;
/*
*/
public class demo01RegisterException {
static String[] usernames = {"张三","李四","王五"};
public static void main(String[] args) throws RegisterException {
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要注册的用户名:");
String username = sc.next();
checkUsername(username);
}
public static void checkUsername(String username) throws RegisterException {
for (String name : usernames) {
if (username.equals(name)){
throw new RegisterException("亲,该用户名已被注册");
}
}
System.out.println("恭喜您注册成功");
}
}
如果用try catch, 我就在catch里面直接return
如果RegisterException继承的是RuntimeException, 那么不需要处理,交给JVM直接中断
9. finally 代码块
try catch后,用finally代码块有助于资源释放
无论程序是否出现异常,最后都要资源释放