该文章Github地址:https://github.com/AntonyCheng/java-notes
在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置文件实现组件的装载,除了这些,模板中还有非常丰富的整合示例,同时单体架构也非常适合SpringBoot框架入门,如果觉得有意义或者有帮助,欢迎Star & Issues & PR!
上一章:由浅到深认识Java语言(26):阶段性练习
39.异常
异常的概念
定义: Java 程序在运行过程中出现的特殊情况,当出现特殊情况时,就需要为不同的情况提供不同的解决方案,以保证程序能够正常运行,即预防异常的状况;
特殊情况指的是用户输入的问题,网络连接的问题,文件未找到的问题等;
这种特殊情况可以在运行时报错时在 Console 控制台内看到;
预防异常示例如下:
package top.sharehome.Bag;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数字:");
try {
int num = sc.nextInt();
int i = 10;
int result = i/num;
System.out.println(result);
}catch (InputMismatchException e) {
// TODO: handle exception
System.out.println("输入的内容不相符");
}catch (ArithmeticException e) {
// TODO: handle exception
System.out.println("不能是零!");
}
System.out.println("!!!!!!!");
}
}
打印效果如下:
异常的分类
广义分类: 父类:Throwable
- Error 错误,这是我们不需要解决的,因为没有办法解决;
- Exception 异常,这是我们应该(必须)解决的;
异常分类:
-
编译时异常:在编译时出现的异常,即编译无法通过,编译时必须处理异常才能开始运行,所以编译时异常能够绝对杜绝异常情况的出现;
-
运行时异常:编译可以通过,即在编译时可以不用处理,在运行时出现了异常,需要事后解决,所以运行时异常并不能够得到绝对的避免,所以我们需要掌握一些常用的运行时异常;
运行时异常属于 RuntimeException 子类;除了运行时异常以外的所有异常都是编译时异常;
常用的运行时异常
-
空指针异常(java.lang.NullPointerException):
示例如下:
package top.sharehome.Bag; public class Demo { public static void main(String[] args) { String str = null; char[] cs = str.toCharArray(); } }
打印效果如下:
-
数组下标越界异常(java.lang.ArrayIndexOutOfBoundsException):
示例如下:
package top.sharehome.Bag; public class Demo { public static void main(String[] args) { char[] c = new char[5]; System.out.println(c[5]); } }
打印效果如下:
-
输入不匹配异常(java.util.InputMismatchException):
示例如下:
package top.sharehome.Bag; import java.util.Scanner; public class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("我们应该输入一个数字,但我却要输入一个字母:"); int nextInt = sc.nextInt(); } }
打印效果如下:
-
算数异常(java.lang.ArithmeticException):
示例如下:
package top.sharehome.Bag; public class Demo { public static void main(String[] args) { int num = 1/0; } }
打印效果如下:
-
类型转换异常(java.lang.ClassCastException):
示例如下:
package top.sharehome.Bag; public class Demo { public static void main(String[] args) { A a = new B(); //向上转型 C c = (C)a; //向下转型的 } } class A{ } class B extends A{ } class C extends A{ }
打印效果如下:
查询其他运行时异常的方法
-
在 Eclipse 中使用 Ctrl+Shift+T 调出 Open Type 窗口;
-
在搜索框中输入 Exception ,找到该类;
-
进入类之后,然后使用 Ctrl+T,调出其子类;
-
再在搜索框中搜索 RuntimeException 后进入,若要查询编译时异常,则查询除 RuntimeException 以外的异常即可;
-
进入该子类之后,再次使用 Ctrl+T 即可看到该类中所包含的运行时异常;
异常生成机制
抛抓模式
当异常对象被创建并抛出时,程序就会遇到这个异常,遇到异常之后,如果没有任何的处理方法,那么 main 方法碰到异常程序终止,如果遇到异常后有处理方案(try-catch),那么就会去匹配 catch 分支,查看 catch 里的异常类型是否与抛出的异常类型相同,如果相同,就运行该 catch 分支中的语句,就表示该异常被处理,如果所有的 catch 分支都没有与该异常类型匹配,那么该异常还是会来到 main 方法中,然后程序终止;
当异常被处理时,catch 里的异常对象能够获取一些该异常的信息, catch 中的异常对象的常用方法:
- e.getMessage();
- e.printStackTrace();
异常的处理方案
示例如下:
以 io 流(后续学习)访问系统内存为例,D: 盘中没有 abc.java 这个文件,我们来访问它;
package top.sharehome.Bag;
import java.io.FileInputStream;
public class Demo {
public static void main(String[] args) {
FileInputStream fis = new FileInputStream("d:/abc.java");
}
}
报错效果如下:
这里给了我们两个选择,一种是将异常向上抛,一种是 try-catch-finally 处理方式
热处理异常
即使用 try-catch-finally 结构;
-
try-catch-catch-…… 语法:
我们将可能出现异常的代码语句放入 try 语句中,如果没有出现异常,就按照原计划执行;
若出现异常就会选择进入后续的 catch 语句,若出现相匹配的异常类型,则执行对应 catch 内容,同时舍弃该 catch 之后的 catch 代码;若没有出现相匹配的异常,该程序就会被系统自动处理,在控制台进行报错;
示例如下:以输入不匹配异常为例;
package top.sharehome.Bag; import java.util.InputMismatchException; import java.util.Scanner; public class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("输入数字正常执行,非数字异常执行:"); try { int num = sc.nextInt(); System.out.printf("num = %d",num); } catch (InputMismatchException e) { //这里已经找到所匹配的异常,即使下面的 Exception 也满足条件,也不会执行了 // TODO: handle exception System.out.println("输入错误!!"); }catch (ArrayIndexOutOfBoundsException e) { // TODO: handle exception System.out.println("指针内存溢出!"); }catch (NullPointerException e) { // TODO: handle exception System.out.println("空指针异常!"); }catch (ArithmeticException e) { // TODO: handle exception System.out.println("计算异常!"); }catch (Exception e) { // TODO: handle exception System.out.println("出现异常!"); } } }
打印效果如下:
-
try-finally 语法:
finally 后的代码指的是无论出现异常,都必须要执行的代码,在该语法结构中,finally 的优先级甚至大于 return;
一串正常代码中,一旦遇到 return ,就会终止程序,返回该返回的值,但是在该结构中即使返回了应该返回的值,依然还会执行 finally 中的代码;
示例如下:
package top.sharehome.Bag; public class Demo { public static void main(String[] args) { int num = method(); System.out.println("num+num=" + num); } public static int method() { try { int num = 10 / 5; return num + num; } finally { // TODO: handle finally clause System.out.println("我必须得执行!"); } } }
打印效果如下:
-
try-catch-catch-……-finally 语法:
该结构是以上两种情况的结合;
示例如下:
package top.sharehome.Bag; import java.util.InputMismatchException; import java.util.Scanner; public class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("输入数字正常执行,非数字异常执行:"); try { int num = sc.nextInt(); System.out.printf("num = %d",num); } catch (InputMismatchException e) { //这里已经找到所匹配的异常,即使下面的 Exception 也满足条件,也不会执行了 // TODO: handle exception System.out.println("输入错误!!"); }catch (ArrayIndexOutOfBoundsException e) { // TODO: handle exception System.out.println("指针内存溢出!"); }catch (NullPointerException e) { // TODO: handle exception System.out.println("空指针异常!"); }catch (ArithmeticException e) { // TODO: handle exception System.out.println("计算异常!"); }catch (Exception e) { // TODO: handle exception System.out.println("出现异常!"); }finally { System.out.println("运行时异常排除完毕!"); } } }
打印效果如下:
冷处理编译时异常
即向上抛
先用未能找到文件异常(编译时异常)来引出问题,以 io 流(后续学习)访问系统内存为例,D: 盘中没有 abc.java 这个文件,我们来访问它;
示例如下:
package top.sharehome.Bag;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Demo {
public static void main(String[] args) throws FileNotFoundException {
m1();
}
static void m1() throws FileNotFoundException {
m2();
}
static void m2() throws FileNotFoundException {
m3();
}
static void m3() throws FileNotFoundException {
m4();
}
static void m4() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("d:/abc.java");
}
}
此时编译时异常就不会出现报错,运行程序若没有出现异常就不会报错,若出现异常就终止程序;
由于该异常申请是从各个方法抛出,直到抛给 main 方法才得以解决,所以称之为向上抛;
我们也可以在中途使用热处理将其解决:
package top.sharehome.Bag;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Demo {
public static void main(String[] args) {
m1();
}
static void m1() {
try {
m2();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static void m2() throws FileNotFoundException {
m3();
}
static void m3() throws FileNotFoundException {
m4();
}
static void m4() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("d:/abc.java");
}
}
此时就结束向上抛异常这样的操作;
自定义异常
**示例如下:**设计一个遇到负数就报错的异常;
NegativeNumberException 类:
package top.sharehome.Bag;
public class NegativeNumberException extends Exception{
//因为继承的是Exception,所以这里是一个编译时异常
//如果继承RuntimeException,这里就是一个运行时异常
//以下代码均是继承后的方法重写代码
public NegativeNumberException() {
super();
// TODO Auto-generated constructor stub
}
public NegativeNumberException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public NegativeNumberException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public NegativeNumberException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public NegativeNumberException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}
Demo 类:
package top.sharehome.Bag;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
try {
int num = sc.nextInt();
//这里需要判断一下抛出自定义异常的条件和内容
if (num < 0) {
throw new NegativeNumberException("该数不能是负数!");
}
} catch (InputMismatchException e) {
System.out.println("输入不匹配;");
} catch (NegativeNumberException e) {
// 以下是自定义异常的效果;
// TODO: handle exception
String message = e.getMessage();
System.out.println(message);
}
}
}
打印效果如下: