目录
? 异常,在Java程序中指的是:因程序问题而中断程序执行的现象。
? 在Java中,为了维护程序正常执行,Java提供了处理异常的异常机制(异常类)。
? 在Java提供的异常机制中,其中java.lang.Throwable是根类,而根类的派生类有java.lang.Error和java.lang.Excepiton两个子类。
? Error,错误(绝症),该类型异常在程序中无法处理,只能尽量避免。
? Excepiton,编译期异常(写源代码时)(小毛病,比如:类似感冒),该类型异常在程序中是可处理的。Excepiton类型还有一个子类RunTimeException,表示运行期异常(程序运行的过程中),该类型异常在程序中也是可处理的。
? 为了更好的区分以上描述的异常分类,我们看以下程序。
// 【Error异常】
// Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
// 内存溢出。超出了分配给JVM内存大小。
// 该程序只能修改源代码解决问题。
int[]nums = new int[1024*1024*1024];
// 【Exception异常】
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
// Unhandled exception: java.text.ParseException
// 此处在编写源代码时就发生异常,该异常后续可以通过相关的处理机制处理和避免
Date date = format.parse("2083-10-10");
// 【RunTimeException异常】
int[] nums = {1,2,3};
// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
// 在程序运行时出现的异常,数组下标超出。该异常可以通过相关异常机制处理
System.out.println(nums[4]);
在编程中,为了更好的处理异常,我们首先要了解异常产生的过程。下面通过一段异常代码来分析。
代码:
// 需求:定义一个方法,用来获取指定数组的指定位置的元素
public static void main(String[] args) {
int[]nums = {1,2,3};
System.out.println(getElement(nums,4));
}
public static int getElement(int[]arr,int index){
return arr[index];
}
分析:
图解:
异常相关的关键字有:
try
catch
finally
throw
throws
作用:在指定的方法内部抛出异常。
格式:throw new xxxException(参数)
注意事项:
代码:
public static void main(String[] args) {
int[]nums = {1,2,3};
// getElement(nums,4); // 异常:java.lang.ArrayIndexOutOfBoundsException: 索引越界:4
int[]nums2=null;
getElement(nums2,0); // 异常java.lang.NullPointerException: 传入的数组对象为null
}
public static int getElement(int[]arr,int index){
if(arr==null){
throw new NullPointerException("传入的数组对象为null");
}
if(index<0||index>=arr.length){
throw new ArrayIndexOutOfBoundsException("索引越界:" + index);
}
return arr[index];
}
? Objects中提供了一个方法,可以检测一个对象为null并抛出异常,我们来应用一下,并查看其源代码更好的理解throw关键字的应用。
方法名称:public static <T> T requireNonNull(T obj)
:查看指定引用对象不是null。
源代码:
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
应用:
public static void main(String[] args) {
int[]nums = {1,2,3};
// getElement(nums,4); // 异常:java.lang.ArrayIndexOutOfBoundsException: 索引越界:4
int[]nums2=null;
getElement(nums2,0); // 异常java.lang.NullPointerException
}
public static int getElement(int[]arr,int index){
Objects.requireNonNull(arr); // 应用
if(index<0||index>=arr.length){
throw new ArrayIndexOutOfBoundsException("索引越界:" + index);
}
return arr[index];
}
当程序抛出一个异常对象给调用者时,调用者必须要处理异常,此时可以选择throws关键字来处理。
throws关键字的作用就是把异常对象继续抛给其他调用者,若其他调用者没有处理异常,则最终会抛给JVM来处理。
格式:
/*
修饰符 返回值类型 方法名() throws XXX1Exception,XXX2Exception... {
throw new XXX1Exception("产生的原因");
throw new XXX2Exception("产生的原因");
}
*/
注意事项:
代码
// 需求:定义一个读取文件的方法,检测文件的路径和后缀名
public static void main(String[] args) throws Exception {
retFile("a.txt");
}
// 读取文件的方法
// private static void retFile(String path) throws FileNotFoundException,IOException {
private static void retFile(String path) throws IOException {
// 如果后缀名不是.txt则抛出
if(!path.contains(".txt")){
throw new FileNotFoundException("文件后缀名不是.txt");
}
if(path.contains("c:")) {
throw new IOException("文件路径错误");
}
}
throws声明异常的弊端是:异常后续代码无法执行(因为交给了JVM,JVM会终止程序)。
try-catch可以让调用者处理异常,并会继续执行后续程序。
格式
try {
// 可能会发生异常的程序
// 若发生异常,try会检测到异常对象
}catch(异常类型 变量) {
// catch会接收到异常对象,可以在此代码块中进行处理
}catch(异常类型 变量) {
// catch会接收到异常对象,可以在此代码块中进行处理
}...
throwable中常用的异常方法
代码
// 需求:定义一个读取文件的方法,检测文件的路径和后缀名
public static void main(String[] args) {
try{
retFile("d.txt");
}catch (Exception e) {
e.printStackTrace();
}
System.out.println("后续代码");
/*
执行结果:
java.io.IOException: 文件路径错误
at it.leilei.cn.demo01.Main01.retFile(Main01.java:27)
at it.leilei.cn.demo01.Main01.main(Main01.java:12)
后续代码
*/
}
// 读取文件的方法
private static void retFile(String path) throws IOException {
// 如果后缀名不是.txt则抛出
if(!path.contains(".txt")){
throw new FileNotFoundException("文件后缀名不是.txt");
}
if(!path.contains("c:")) {
throw new IOException("文件路径错误");
}
}
finally关键字的作用:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行 不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
finally使用格式:try...catch...finally自身需要处理异常,最终还得关闭资源。
finally关键字的应用场景:当我们在try语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等),我们都得在使用完之后,最终关闭打开的资源。
代码:
// 需求:定义一个读取文件的方法,检测文件的路径和后缀名
public static void main(String[] args) {
try{
retFile("d.txt");
}catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println("释放资源");
}
System.out.println("后续代码");
}
// 读取文件的方法
private static void retFile(String path) throws IOException {
// 如果后缀名不是.txt则抛出
if(!path.contains(".txt")){
throw new FileNotFoundException("文件后缀名不是.txt");
}
if(!path.contains("c:")) {
throw new IOException("文件路径错误");
}
}
多个异常使用捕获又该如何处理呢?
一般我们是使用一次捕获多次处理方式,格式如下:
格式:
try{
编写可能会出现异常的代码
}catch(异常类型A e){
当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){
当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异
常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。
运行时异常被抛出可以不处理。即不捕获也不声明抛出(JVM默认会进行处理)。
如果finally有return语句,永远返回finally中的结果,避免该情况.
public static void main(String[] args) {
int num = getNum();
System.out.println(num); // 100
}
// 读取文件的方法
public static int getNum() {
int a = 10;
try {
return a;
}catch (Exception e){}
finally {
a = 100;
return a;
}
}
如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异 常。
class Fu{
// 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异 常。
public void show1() throws IndexOutOfBoundsException{};
}
class Zi extends Fu{
// 子类重写父类方法时,抛出和父类相同的异常
// public void show1() throws IndexOutOfBoundsException{};
// 或者是父类异常的子类ArrayIndexOutOfBoundsException 继承 IndexOutOfBoundsException
// public void show1() throws ArrayIndexOutOfBoundsException{};
// 不抛出异常
public void show1() {};
}
? 我们说了Java中不同的异常类,分别表示着某一种具体的异常情况,那么在开发中总是有些异常情况是SUN没有定义好的,此时我们根据自己业务的异常情况来定义异常类。例如年龄负数问题,考试成绩负数问题等等。
? 在开发中根据自己业务的异常情况来定义异常类.
? 自定义一个业务逻辑异常: RegisterException。一个注册异常类。
要求:我们模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。
public static void main(String[] args) {
// 接收用户注册的用户名
String name = new Scanner(System.in).next();
try{
check(name);
}catch (RegisterException e){
e.printStackTrace();
return;
}
System.out.println("注册成功");
}
public static void check(String n) throws RegisterException{
String[]users={"张三","李四","王五"};
for (int i = 0; i < users.length; i++) {
if (n.equals( users[i])) {
throw new RegisterException("亲,该用户名已经注册");
}
}
}
public class RegisterException extends Exception{
public RegisterException(){
super();
}
public RegisterException(String message){
super(message);
}
}
?
原文:https://www.cnblogs.com/lpl666/p/12004769.html