异常-java

目录

一、异常的概念和体系结构

   1.1 异常的概念

  1.2 异常的体系结构

  1.3 异常的分类

二、异常的处理

    2.1 防御式编程

   2.2 异常抛出

   2.3 异常捕获

  2.4 异常处理流程

三、自定义异常类

一、异常的概念和体系结构

   1.1 异常的概念

              程序员在开发过程中,想要将代码写得尽可能完美,但在程序运行过程中,会出现一些问题,例如:数据的格式不正确、网络不畅等。在Java中,将程序执行过程中发生的不正常行为叫作异常,例如写代码时遇到的:

        1. 算术异常

System.out.println(10/0);

       2. 数组越界异常

int[] arr={1,2,3};

System.out.println(arr[5]);

        3. 空指针异常

int[] arr=null;

System.out.println(arr.length);

         Java中不同类型的异常,都有对应的类进行描述。

  1.2 异常的体系结构

        异常的种类有很多,为对不同类异常或错误进行更好的管理,Java内部维护一个异常体系结构。

        

       由图可知,Throwable是异常体系最顶层的类,有Error和Exception两个子类;Error类异常是Java虚拟机无法解决的问题,例如资源耗尽等,一旦出现这类异常后面的程序就不再执行Exception类异常是程序员可以通过代码处理的,使程序继续进行

  1.3 异常的分类

        异常发生在编译期间或程序运行时,根据发生的时机不同可以分为编译时异常和运行时异常。上图中只有Runtime Exception类是运行时异常

        1. 编译时异常

        编译时异常是在程序编译期间发生的异常,也叫受检查异常。

class Person{String name;public Person(String name){this.name=name;}@Overrideprotected Object clone() {return super.clone();}
}

        

        必须捕获或声明(方法后声明)异常来方便抛出,异常最后后由JVM来处理。

        2. 运行时异常

        运行时异常时在程序运行期间发生的异常,也叫非受检查异常。上述所说的数组越界异常和空指针异常都是运行时异常,编译通过但运行出错。

        注意:编译时期出现的语法错误不属于异常

二、异常的处理

    2.1 防御式编程

        防御式编程是程序出现问题及时通知程序员进行处理,处理方式有两种:事前防御型和事后认错型。

        1. 事前防御型:在操作之前就做检查。

boolean ret=false;

ret =登陆游戏();

if(!ret){

        //处理游戏错误;

        return;
}

ret=开始匹配();

if(!ret){

        //处理匹配错误;

        return;

}

ret=游戏确认();

if(!ret){

        //处理游戏确认错误;

        return;

}

ret=选择英雄();

if(!ret){

        //处理选择英雄错误;

        return;

}

……

        缺陷:正常流程和错误处理流程写一块,代码整体阅读性不高。

        2. 事后认错型:先操作,遇到问题再处理。

        try{

                登陆游戏();

                开始匹配();

                游戏确认();

                选择英雄();

                ……

        }catch(登录游戏异常){

                //处理登录游戏异常;

        }catch(开始匹配异常){

                //处理开始匹配异常;

        }catch(游戏确认异常){

                //处理游戏确认异常;

        }catch(选择英雄异常){

                //处理选择英雄异常;

        }

        ……

        优点:正常流程和错误流程的代码分开,代码阅读性高,容易理解代码异常处理的核心思想是事后认错型。

        Java中,异常处理主要的5个关键字:throw、try、catch、final、throws

   2.2 异常抛出

        在编写程序时,如果程序中出现错误,就需要将错误信息告诉给调用者。

        在Java中。可以借助throw关键字,抛出一个指定的异常对象,将错误信息告诉给调用者

   throw new  XXXException("异常产生原因");

        示例:访问数组任意位置元素的方法

public  static int  getEldment(int[] arr,int index){if(null==arr)throw new NullPointerException("传递的数组为空");if(index<0||index>= arr.length)throw  new ArrayIndexOutOfBoundsException("数组下标越界");return arr[index];
}public static void main(String[] args) {int[] arr={1,2,3};System.out.println(getEldment(arr,3));
}

        注意:throw必须写在方法体内;抛出的异常必须是Exception或Exception的子类对象;如果是Runtime Exception或者Runtime Exception的子类,则可以不用处理,交给JVM处理;如果抛出的是编译异常,用户必须处理,否则无法通过编译;异常一旦抛出,其后的代码就不会执行

   2.3 异常捕获

        异常捕获是异常的具体处理方法,主要有两种:异常声明throws和try-catch捕获处理

        1. 异常声明 throws

        在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理,可以借助throws将异常抛给方法的调用者来处理,即当前方法不处理异常,提醒方法的调用者处理异常

        语法格式

修饰符  返回值类型 方法名(参数列表) throws 异常类型1,异常类型2...{

}

        示例:加载指定配置文件

File file;
//FileNotFoundException:编译时异常,表明文件不存在
//没有办法处理,将错误信息报给调用者,让调用者检查文件名是否错误
public  void OpenFile(String Filename) throws FileNotFoundException{if(!Filename.equals("config.ini")){throw  new FileNotFoundException("配置的文件名不对");}

        注意:throws必须跟在方法的参数列表之后;声明的异常必须是Exception或Exception的子类;方法内部如果抛出多个异常,throws之后就必须跟多个异常,如果抛出的多个异常,则直接声明父类即可;调用声明抛出异常的方法时,调用者必须对异常进行处理,或者使用throws抛出

public class Config {File file;/*public void OpenFile(String FileName) throws IOException,FileNotFoundExceptionFileNotFoundException 继承于IOException*/public void OpenFile(String FileName) throws IOException{if(FileName.endsWith(".ini")){throw  new IOException("该文件不是.ini文件");}if(FileName.equals("config.ini")) {throw new FileNotFoundException("配置的文件名不对");}}public static void main(String[] args) {Config config=new Config();try {config.OpenFile("config.ini");} catch (IOException e) {e.printStackTrace();}}
}

        2. try-catch捕获并处理

        throws对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch。
        语法格式

try{

        //可能出现异常的代码

}catch(捕获的异常类型 e){

        //如果捕获到,就处理异常,完成后跳出try-catch结构,继续执行后面代码

}[catch(异常类型 e){

        //异常处理

}finally{

        //此处代码一定执行

}]

//后面代码

//当异常被捕获并处理后,后面代码一定会执行,如果捕获类型不对,后面代码就不会执行

        上面代码块中[]表示可选项,可以添加也可以不添加,try中代码可能会抛出异常也可能不会。

public static void main(String[] args) {System.out.println("异常前");/*catch可以捕获多个异常,但同一时刻只能抛出一个异常*/try{System.out.println(10/0);}catch (ArithmeticException e){e.printStackTrace();//打印信息最全面System.out.println("成功捕获并处理ArithmeticException异常");//System.out.println(e.getMessage());//只打印异常信息//System.out.println(e);//打印异常类型:异常信息}catch (NullPointerException e){e.printStackTrace();System.out.println("成功捕获并处理NullPointerException异常");}System.out.println("异常后");
}

        

        异常处理方式:根据不同的场景来决定。对于比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果;对于不太严重的问题(大多数场景), 可以记录错误日志, 通过监控报警程序及时通知程序员;对于可能会恢复的问题(和网络相关的场景), 可以尝试进行重试。在以上代码中采取的是经过简化的第二种方式. 我们记录的错误日志是出现异常的方法调用信息, 能很快速的让我们找到出现异常的位置。
        注意:try块内抛出异常位置后的代码不会被执行;如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到JVM收到后结束程序----异常按照类型来捕获;

public static void main(String[] args) {try{int[] arr={1,2,3};System.out.println(arr[3]);//抛出数组越界异常}catch (NullPointerException e){//捕获空指针异常,其他类的异常无法被捕获e.printStackTrace();}System.out.println("异常处理后");
}

        try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获;

public static void main(String[] args) {try{int[] arr={1,2,3};System.out.println(arr[3]);//抛出数组越界异常}catch (NullPointerException e){//捕获空指针异常,其他类的异常无法被捕获System.out.println("空指针异常");e.printStackTrace();}catch (ArrayIndexOutOfBoundsException e){//数组越界异常System.out.println("数组越界异常");e.printStackTrace();}System.out.println("异常处理后");
}

        

        如果多个异常处理方式完全相同,也可以以如下方式写;

catch (NullPointerException|ArrayIndexOutOfBoundsException e){

}

        如果异常间有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误,如下代码;

public static void main(String[] args) {try{int[] arr={1,2,3};System.out.println(arr[5]);}catch (Exception e){e.printStackTrace();}catch (NullPointerException e){e.printStackTrace();}
}

//Exception 'java.lang.NullPointerException' has already been caught

        3. finally

        写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库连接等,在程序正常或者异常退出时,必须要对资源进行回收。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的。

        语法格式

try{

        //可能异常的代码

}catch(异常类型 e){

        //处理异常

}finally{

        //此处代码一定执行,不论是否异常

}

        示例

public static void main(String[] args) {try{int[] arr = {1,2,3};arr[5] = 10;arr[0] = 10;}catch (ArrayIndexOutOfBoundsException e){System.out.println("处理异常");e.printStackTrace();}finally {System.out.println("finally中的代码一定会执行");}System.out.println("异常后");
}

        

        finally 和 try-catch-finally 后的代码都会执行,那为什么还要有finally呢?
        示例:在一个方法中输入一个整数并返回,在main中打印这个数

public static int getData(){Scanner sc = null;try{sc = new Scanner(System.in);int data = sc.nextInt();return data;}catch (InputMismatchException e){e.printStackTrace();}finally {System.out.println("finally中代码");}System.out.println("try-catch-finally之后代码");if(null != sc) {sc.close();}return 0;
}
public static void main(String[] args) {int date=getData();System.out.println(date);
}

        

        上述代码,正常输入,成功接收输入后程序就返回了,try-catch-finally之后代码没有执行,即输入流没有被释放,造成资源泄漏。
        注意:finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作

public static void main(String[] args) {System.out.println(func());
}
public static int func() {try {return 5;} finally {return 10;}
}

        

finally 的执行是在方法返回之前(try 或者catch中若有return,会在这个return之前执行finally),但若finally中也存在return 语句, 那么就会执行finally中的return, 而不会执行try中的 return。一般不建议在finally中写return。

  2.4 异常处理流程

        如果本方法中没有合适的处理异常的方式, 就会沿着调用栈向上传递。

public static void main(String[] args) {
        try {
                func1();
        } catch (ArrayIndexOutOfBoundsException e) {
                e.printStackTrace();
        }

        System.out.println("after try catch");
}
public static void func1() {
        int[] arr = {1, 2, 3};
        System.out.println(arr[100]);
}

        

        异常处理流程:程序先执行 try 中的代码;如果 try 中代码异常, 就结束 try 中代码, 看与catch 中的异常类型是否匹配;如果找到匹配的异常类型, 就会执行 catch 中的代码;如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者;无论是否找到匹配的异常类型, finally 中的代码都会被执行(在该方法结束前);如果上层调用者也没有处理的了异常, 就继续向上传递;一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止。

三、自定义异常类

        Java中虽然已经内置丰富的异常类, 但不能完全表示实际开发所遇到的一些异常,此时需要维护符合我们实际情况的异常结构。

        例如:实现一个用户登陆功能

public class LogIn {

        //用户名
        private String user_name = "admin";

        //密码
        private String user_password = "123456";

        //登录
        public static void loginInfo(String userName, String password) {
                if (!userName.equals(userName)) {


                } if(!password.equals(password)) {


                }

                System.out.println("登陆成功");
        }
        public static void main(String[] args) {
                loginInfo("admin", "123456");
        }
}

        在处理用户名密码错误时可能需要抛出两种异常,我们可以基于已有的异常类进行扩展(继承), 创建和业务相关的异常类。

        自定义异常类,然后继承自Exception 或者 RunTimeException;实现一个带有String类型参数的构造方法,参数含义:出现异常的原因。

public class UserNameException extends Exception{public UserNameException(String massage){super(massage);}
}
public class UserPasswordException extends Exception{public  UserPasswordException(String massage){super(massage);}
}
public class Login {//用户名private String user_name="admin";//密码private String user_password="123456";//登录public static void User_login(String user_name,String user_password) throws UserNameException,UserPasswordException{if(!user_name.equals(user_name)){throw new UserNameException("用户名错误!");}if(!user_password.equals(user_password)){throw new UserPasswordException("用户密码错误!");}System.out.println("登录成功");}public static void main(String[] args) throws UserPasswordException,UserNameException {try{User_login("admin","123456");}catch (UserNameException e){e.getStackTrace();}catch (UserPasswordException e){e.getStackTrace();}}
}

        注意:自定义异常通常会继承自 Exception 或者 RuntimeException;继承自 Exception 的异常默认是受查异常;继承自 RuntimeException 的异常默认是非受查异常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/69824.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Centos7 + Apache Ranger 2.4.0 部署

一、Ranger简介 Apache Ranger提供一个集中式安全管理框架, 并解决授权和审计。它可以对Hadoop生态的组件如HDFS、Yarn、Hive、Hbase等进行细粒度的数据访问控制。通过操作Ranger控制台,管理员可以轻松的通过配置策略来控制用户访问权限。 1、组件列表 # Service Name Liste…

Springboot - 13.spring-boot-starter-security集成

&#x1f440;Spring Boot Starter Security 中文文档 Spring Security中文文档 &#x1f440;Spring Boot Starter Security 运行流程 当然可以。首先&#xff0c;我们会将用户存储和认证的流程融入整个Spring Boot Starter Security的使用流程中。以下是当你使用Spring Bo…

Excel VSTO开发4 -其他事件

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 4 其他事件 针对插件的事件主要有Startup、Shutdown这两个事件&#xff0c;在第2节中已经讲解。在开发窗口中&#xff0c;选择对象…

“谁天生是项目经理?四大特质决定你的机会“

大家好&#xff0c;我是老原。 但其实不少刚开始尝试项目管理的人&#xff0c;包括老原自己也曾经遇到过这样的问题&#xff1a; ▪ 自己没权没势&#xff0c;大家凭什么听我的&#xff1f; ▪ 资源受限&#xff0c;如何向老板争取更多资源&#xff1f; ▪ 怎样才能推进多方…

WebAssembly 在云原生中的实践指南

1 WebAssembly 介绍 WebAssembly&#xff08;Wasm&#xff09;是一种通用字节码技术&#xff0c;它可以将其他编程语言&#xff08;如 Go、Rust、C/C 等&#xff09;的程序代码编译为可在浏览器环境直接执行的字节码程序。 WebAssembly 的初衷之一是解决 JavaScript 的性能问…

【月报】Aavegotchi 开发进度更新 - 2023 年 8 月

嗨&#xff0c;Gotchigang&#xff01;2023 年的进程已经过了一半&#xff0c;我们团队一直在努力推动 Aavegotchi 生态系统迈向新的高度&#xff01;在本月的开发更新中&#xff0c;我们将分享在以下方面取得的进展&#xff1a; ● Gotchi 游戏 ● Gotchichain ● Aavegotc…

【iVX】十五分钟制作一款小游戏,iVX真有怎么神?

个人主页&#xff1a;【&#x1f60a;个人主页】 新人博主&#xff0c;喜欢就关注一下呗~ 文章目录 前言iVX介绍初上手布置背景制作可移动物体总结&#xff08;完善步骤&#xff09; 前言 在上篇文章中&#xff0c;我向大家介绍了一种打破常规的编程方式——iVX&#xff0c;可…

Go map转json

在Go中如何返回前端 字段名称/数量都不确定的json数据&#xff1f; 之前用Go写web服务&#xff0c;返回给前端的json格式的接口&#xff0c;有哪些要返回的字段都是明确的。都是预先定义一个结构体&#xff0c;json.Marshal一下即可~ 但当有的场景&#xff0c;要返回哪些字段不…

RabbitMQ:hello结构

1.在Linux环境上面装入rabbitMQ doker-compose.yml version: "3.1" services:rabbitmq:image: daocloud.io/library/rabbitmq:managementrestart: alwayscontainer_name: rabbitmqports:- 6786:5672- 16786:15672volumes:- ./data:/var/lib/rabbitmq doker-compos…

【C++】函数重载 ④ ( 函数指针定义的三种方式 | 直接定义函数指针 | 通过 函数类型 定义 函数指针 | 通过 函数指针类型 定义 函数指针 )

文章目录 一、函数指针定义方法1、直接定义函数指针2、通过 函数类型 定义 函数指针3、通过 函数指针类型 定义 函数指针4、代码示例 - 不同方式定义函数指针 博客总结 : 重载函数 : 使用 相同 的 函数名 , 定义 不同 的 函数参数列表 ;判定标准 : 只有 函数参数 的 个数 / 类…

安全狗亮相厦门市第五届网络安全宣传周开幕式

9月5日&#xff0c;厦门市第五届网络安全宣传周开幕式成功举行。 作为国内云原生安全领导厂商&#xff0c;安全狗也受邀参与此次大会。 据悉&#xff0c;此次主要包含领导致辞、厦门市第五届网络安全宣传周亮点活动介绍、厦门市第二届网络安全攻防演练优秀组织奖颁奖、厦门市…

SpringMVC之综合示例讲解(用示例来带你学习SpringMVC)

目录 前言 一、SpringMVC之常用注解 1. 注解说明 2. 扩展延伸 3. 注解的作用展示 导入slf4j的相关依赖及配置项目 pom.xml文件 二、参数传递 1. 基础类型String类型 测试代码 测试结果 页面 控制台 2. 复杂类型 测试代码 测试结果 页面 控制台 ​编辑 3. Req…

Linux创建新文件的几种方式

第一种是 vi 文件名&#xff0c;然后进入vi编辑&#xff0c;完了之后保存退出&#xff1b;然后ls看一下&#xff0c;文件有了&#xff1b; 在终端输入 cat > 文件名&#xff0c;这没用过&#xff1b;输入以后回车&#xff0c;不会退出命令&#xff1b;输入一行文字&#xff…

基于jeecg-boot的flowable流程自定义业务退回撤回或驳回到发起人后的再次流程提交

更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/nbcio-boot 前端代码&#xff1a;https://gitee.com/nbacheng/nbcio-vue.git 在线演示&#xff08;包括H5&#xff09; &#xff1a; http://122.227.135.243:9888 主要…

【VL tracking】Towards Unified Token Learning for Vision-Language Tracking

不知道什么原因学校认证账号进不去&#xff0c;下载不了最新的PDF 广西师范大学 | 国科大 | 厦大 代码开源 zhihu指路&#x1f449;【VL tracking】MMTrack阅读 问题 一方面&#xff0c;传统的VL tracking方法需要昂贵的先验知识。例如&#xff0c;一些tracker是专门用于bou…

9月第1周榜单丨哔哩哔哩飞瓜数据B站UP主排行榜发布!

飞瓜轻数发布2023年8月28日-9月3日飞瓜数据UP主排行榜&#xff08;B站平台&#xff09;&#xff0c;通过充电数、涨粉数、成长指数、带货数据等维度来体现UP主账号成长的情况&#xff0c;为用户提供B站号综合价值的数据参考&#xff0c;根据UP主成长情况用户能够快速找到运营能…

vue3 + elementplus Cannot read properties of null (reading ‘isCE‘)

使用命令行直接下载的element-plus&#xff0c;使用时会报错。 卸载掉&#xff0c;然后在项目根目录下&#xff0c;使用vue ui安装依赖&#xff0c; 即可使用

搭建PyTorch神经网络进行气温预测

import numpy as np import pandas as pd import matplotlib.pyplot as plt import torch import torch.optim as optim import warnings warnings.filterwarnings("ignore") %matplotlib inline features pd.read_csv(temps.csv)#看看数据长什么样子 features.he…

leetcode:1941. 检查是否所有字符出现次数相同(python3解法)

难度&#xff1a;简单 给你一个字符串 s &#xff0c;如果 s 是一个 好 字符串&#xff0c;请你返回 true &#xff0c;否则请返回 false 。 如果 s 中出现过的 所有 字符的出现次数 相同 &#xff0c;那么我们称字符串 s 是 好 字符串。 示例 1&#xff1a; 输入&#xff1a;s…

vue中实现签名画板

特意封装成了一个组件&#xff0c;签名之后会生成一张图片 signBoard.vue <template><el-drawer title"签名" :visible.sync"isShowBoard" append-to-body :show-close"false" :before-close"closeBoard" size"50%&quo…