异常
概念
异常:程序中不正常的表现,会导致程序中断执行。
异常就是一个对象,当JVM
检测发现由异常对象时,JVM
就会中断执行。
异常体系介绍【框架】
【Error代码演示】
/*
Java中的Error
OutOfMemoryError 内存溢出错误
*/
public class Demo01 {
public static void main(String[] args) {
int[] arr1 = new int[4];//至少需要16Byte
System.out.println("arr1 = " + arr1);//[I@58ceff1
//OutOfMemoryError
int[] arr2 = new int[Integer.MAX_VALUE];// 21亿 x4 84亿多字节
System.out.println("arr2 = " + arr2);
}
}
当产生异常时一般的操作方式
如果不知道异常类型,可以将异常类型拷贝到API
文档中,查看具体说明。
异常的分类【Exception的分类】
异常产生的过程认识
异常处理关键字的认识
throw
: 异常产生的关键字,方法内部throws
:用在方法声明中,表示将本方法内部的异常甩锅给方法调用处。try-catch
:方法内部进行对异常进行处理inally
:finally
一定要和try-catch
联合使用,表示最终一定会执行的代码块。
异常的产生:throw
格式:
throw 异常对象;
【代码实践】
public class Demo01 {
public static void main(String[] args) {
// String hello = Objects.requireNonNull(null);
requireNonNull(null);
int[] arr = {10, 20, 30};
printArray(arr, 5);
}
/*
打印指定索引的数组元素
*/
public static void printArray(int[] arr, int index) {
if (index < 0 || index >= arr.length) {
//非法索引
throw new ArrayIndexOutOfBoundsException("你的索引非法哦!!"); //运行时异常 产生一个越界异常对象
}
int e = arr[index];
System.out.println(e);
System.out.println("Hello World2");
}
public static void requireNonNull(Object object) {
if (object == null) {
//空指针异常: NullPointerException
throw new NullPointerException("老铁,你的对象空了"); //产生一个空指针异常对象
}
}
}
异常处理方式:throws
throws
:在方法中声明,本方法中有那些异常
这是一种处理方式,如果方法中真的发生了异常,将会把异常甩锅给方法调用处。
【格式】
修饰符 返回值类型 方法名(参数列表) throws 异常1,异常2 {
}
【代码实践】
/*
编译时异常:编译阶段,一定要做处理
IOException
|--FileNotFoundException
ParseException
*/
public class Demo02 {
public static void main(String[] args) throws FileNotFoundException,ParseException {
//String book = findBook("Java入门到精通.txt");
String book = findBook("九阴真经.txt");
System.out.println("book = " + book);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date parse = sdf.parse("2010年10-10");
System.out.println("parse = " + parse);
}
public static String findBook(String bookName) throws FileNotFoundException{
ArrayList<String> books = new ArrayList<>();
Collections.addAll(books, "葵花宝典.txt", "九阴真经.txt", "九阳神功.txt", "C从入门到放弃.txt");
if (!books.contains(bookName)) {
throw new FileNotFoundException("没有你需要的书:" + bookName); // 产生了一个编译时异常
}
System.out.println("恭喜找到了您的书......");
return bookName;
}
}
异常处理方式:try-catch
使用格式:
try{
可能有异常的代码:
调用了有异常的方法;【常用】
自己throw了编译时异常;【不常见】
}catch(异常类型 变量){
这个变量就是捕获的异常对象
}
【代码实践】
public class Demo02 {
public static void main(String[] args) {
try {
//String book = findBook("Java入门到精通.txt");
String book = findBook("九阴真经.txt"); //FileNotFoundException
System.out.println("book = " + book);
} catch (FileNotFoundException e) {
e.printStackTrace();//打印异常信息
}
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date parse = sdf.parse("2010年10-10");
System.out.println("parse = " + parse);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("Hello World!!!!!!!!!!");
}
public static String findBook(String bookName) throws FileNotFoundException{
ArrayList<String> books = new ArrayList<>();
Collections.addAll(books, "葵花宝典.txt", "九阴真经.txt", "九阳神功.txt", "C从入门到放弃.txt");
if (!books.contains(bookName)) {
throw new FileNotFoundException("没有你需要的书:" + bookName); // 产生了一个编译时异常
}
System.out.println("恭喜找到了您的书......");
return bookName;
}
}
执行流程:
try-catch
一次性处理多个异常
格式:
try{
可能有异常的代码:
调用了有异常的方法;【常用】
自己throw了编译时异常;【不常见】
}catch(异常类型 变量){
这个变量就是捕获的异常对象
}catch(异常类型 变量){
这个变量就是捕获的异常对象
}catch(异常类型 变量){
这个变量就是捕获的异常对象
}catch(异常类型 变量){
这个变量就是捕获的异常对象
}
如果有存在父子类异常,若要单独处理,子类异常要放在父类异常前面
若不想单独处理子类异常,可以不写子类异常,父类异常可以直接处理子类异常
【代码实践】
/*
异常处理时,父类异常可以接受子类异常
当try-catch处理多个异常时,需要多个catch语句抓捕指定异常
如果有存在父子类异常,若要单独处理,子类异常要放在父类异常前面
若不想单独处理子类异常,可以不写子类异常,父类异常可以直接处理子类异常
*/
public class Demo01 {
public static void main(String[] args) {
try {
test("文件异常");
test("IO异常");
test("日期解析异常");
} catch (FileNotFoundException e) {
String message = e.getMessage();
System.out.println("message = " + message);
} catch (IOException e) {
String message = e.getMessage();
System.out.println("message = " + message);
} catch (ParseException e) {
String message = e.getMessage();
System.out.println("message = " + message);
}
//父类异常可以处理子类异常
try {
test("文件异常");
test("IO异常");
test("日期解析异常");
} catch (Exception e) {
String message = e.getMessage();
System.out.println("message = " + message);
}
System.out.println("Hello World.....");
}
public static void test(String str) throws FileNotFoundException, IOException, ParseException {
if (str.equals("文件异常")) {
throw new FileNotFoundException("文件未找到异常");
}
if (str.equals("IO异常")) {
throw new IOException("IO异常");
}
if (str.equals("日期解析异常")) {
throw new ParseException("日期异常", 100);
}
}
}
关键字finally
的使用:
finally
和try-catch
结合一起使用,表示一定要执行的代码。
格式
try{
}catch(){
}finally{
//一定要执行的代码块
}
使用场景:IO
流使用中,资源的关闭动作,可以放到finally
代码块中。
【代码实践】
public class Demo01 {
public static void main(String[] args) {
String name = goToLibrary();
System.out.println("name = " + name);
}
public static String goToLibrary() {
String book=null;
try {
book = findBook("葵花宝典.txt");
//System.out.println("找书结束");
return book; //葵花宝典.txt
} catch (FileNotFoundException e) {
String message = e.getMessage();
System.out.println("message = " + message);
return null;
}finally {
//保证一定执行,即使真正发生了异常
System.out.println("找书结束");
return "《" + book + "》"; //《葵花宝典.txt》
}
}
public static String findBook(String bookName) throws FileNotFoundException {
ArrayList<String> books = new ArrayList<>();
Collections.addAll(books, "葵花宝典.txt", "九阴真经.txt", "九阳神功.txt", "C从入门到放弃.txt");
if (!books.contains(bookName)) {
throw new FileNotFoundException("没有你需要的书:" + bookName); // 产生了一个编译时异常
}
System.out.println("恭喜找到了您的书......");
return bookName;
}
}
try-catch
处理异常的说明
当一个异常在该方法产生时,思考是否自己可以处理,【自己处理是否有意义】,如果有意义可以使用try-catch,如果自己处理没有任何意义,使用throws甩锅处理让方法调用者去处理。
异常处理时注意事项:
-
运行时异常被抛出可以不处理。即不捕获也不声明抛出。
-
如果父类抛出了多个异常,子类覆盖父类方法时,只能抛出相同的异常或者是他的子集。
-
父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
-
当多异常处理时,捕获处理,前边的类不能是后边类的父类
-
在try/catch后可以追加finally代码块,其中的代码一定会被执行,通常用于资源回收。
-
多个异常使用捕获又该如何处理呢?
多个异常分别处理。
- 多个异常,多次处理。
- 多个异常一次捕获一次处理。【父类异常处理子类异常】
自定义异常类型
-
为什么要自定义异常类?
JDK
中提供了很多异常,当逻辑中要使用的异常类型JDK
没有提供时,就可以自己去定义异常。 -
如何自定义异常类?
定义一个子类继承异常类型
public class 类型 extends 异常类型{ }
-
异常有编译时异常
Exception
,有运行时异常RuntimeException
,该如何选择?编译时异常:要求使用的人强制处理,处理后能够保证程序正常执行
运行时异常:不要求强制处理,但是一旦报错,程序崩溃。
优先选择编译时异常,应该要继承
Exception
-
练习巩固
模拟用户注册账号,如果账号已存在,异常报错
因为
JDK
中不存在一个账号注册异常,需要自己动手创建一个异常类
自定义异常类型:
/*
自定义注册异常
*/
public class RegisterException extends Exception { //编译时异常
public RegisterException() {
}
public RegisterException(String message) {
super(message);
}
}
自定义异常的使用,与JDK
中的异常一样。
public class Demo01 {
public static void main(String[] args) {
try {
boolean result = register("迪丽热巴123", "123123");
} catch (RegisterException e) { //处理捕获的是自己定义的异常
// e.printStackTrace();
String message = e.getMessage();
System.out.println("注册失败:" + message);
}
}
public static boolean register(String username, String password) throws RegisterException {
ArrayList<String> account = new ArrayList<>();
Collections.addAll(account, "迪丽热巴", "古力娜扎", "abc", "aaaa");
if (!account.contains(username)) {
account.add(username);
System.out.println("注册成功!!");
return true;
}
throw new RegisterException("不好意思!!用户名已被占用"); //抛出了一个自定义的编译时异常
}
}