首页 > 其他分享 >异常处理

异常处理

时间:2024-08-18 14:04:55浏览次数:5  
标签:throws 处理 throw try int 异常 public

异常

在Java中,异常(Exception)是指程序执行过程中可能出现的不正常情况或错误。它是一个事件,会干扰程序的正常执行流程,并可能导致程序出现错误或崩溃。

异常体系

异常的根类是java.lang.Throwable,Java提供的所有异常类均继承自此类,其下有两个子类:java.lang.Errorjava.lang.Exception,平常所说的异常指java.lang.Exception

image-20240730105155420

Throwable体系:

  • Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。
    • 例如: StackOverflowErrorOutOfMemoryError
  • Exception(编译时异常):表示异常,其它因编程错误或偶然的外在因素导致的一般性问题,程序员可以通过相应预防处理措施,使程序发生异常后还可以继续运行。好比感冒、阑尾炎。
    • 例如:空指针访问、试图读取不存在的文件、网络连接中断、数组角标越界

Exception

是我们通常说的异常和异常处理。Exception异常又通常分两大类:

运行期异常(unchecked Exception):这类异常的发生多数是因为程序员编写的代码逻辑不够严谨造成的(如数组脚标越界异常),可以选择进行处理或不处理,最好是通过修正、优化代码避免异常的发生或者使用异常处理简化复杂的逻辑判断代码)。

@Test
public void test01(){
    //NullPointerException
	int[] arr=null;
	System.out.println(arr.length);
}

@Test
public void test02(){
	//ClassCastException
	Person p = new Man();
	Woman w = (Woman) p;
}

@Test
public void test03(){
	//ArrayIndexOutOfBoundsException
	int[] arr = new int[5];
	for (int i = 1; i <= 5; i++) {
		System.out.println(arr[i]);
	}
}

@Test
public void test04(){
	//InputMismatchException
	Scanner input = new Scanner(System.in);
	System.out.print("请输入一个整数:");
	int num = input.nextInt();
}

@Test
public void test05(){
	int a = 1;
	int b = 0;
	//ArithmeticException
	System.out.println(a/b);
}

编译期异常(checked Exception):这类异常一般由程序之外的因素引起的(如程序读取的文件不存在、网络中断),而不是程序员写的代码逻辑有问题,所以程序员容易忽略对这类异常的处理,而恰恰这类异常又很常发生,所以Java要求针对这类可能发生的异常必须进行处理,否则编译无法通过。(只有java语言有需强制处理的异常)

@Test
public void test06() throws InterruptedException{
	Thread.sleep(1000);//休眠1秒
}

@Test
public void test07() throws FileNotFoundException{
	FileInputStream fis = new FileInputStream("Java学习秘籍.txt");
}

@Test
public void test08() throws SQLException{
	Connection conn = DriverManager.getConnection("....");
}

异常的生成与抛出机制throw

Java程序的执行过程中如出现异常,会生成一个异常类对象,然后该异常对象会被提交给Java运行时系统,这个过程称为抛出(throw)异常。异常对象的生成与抛出有两种方式:

1.虚拟机自动生成

由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,就会在后台自动创建一个对应异常类的实例对象自动抛出

// 工具类
public class ArrayTools {
    // 对给定的数组通过给定的角标获取元素。
    public static int getElement(int[] arr, int index) {
        int element = arr[index];
        return element;
    }
}
// 测试类
public class ExceptionDemo {
    public static void main(String[] args) {
        int[] arr = { 34, 5, 67 };
        intnum = ArrayTools.getElement(arr, 4)
        System.out.println("num=" + num);
        System.out.println("over");
    }
}
/*
一旦发生了异常 就会产生一个异常对象 当前方法是否对异常进行了处理 如果没有处理则沿着方法的调用关系逐级向上抛出,直到抛给jvm; 
抛给了jvm    1.结束/终止程序  2.打印异常的详细信息   异常的类型 异常的原因 异常的抛出流程
 */

image-20240730110332097

2.由开发人员手动创建

由开发人员手动创建:Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样,手动创建的异常对象需要手动抛出,才会对程序产生影响。

在Java中,使用关throw关键字手动抛出一个异常对象,throw用在方法内,将这个异常对象传递到方法调用者处,同时结束当前方法的执行。

使用格式:

throw new 异常类名(参数);

例如:

throw new NullPointerException("要访问的arr数组不存在");

throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");

throw的使用示例:

public class ThrowDemo {
    public static void main(String[] args) {
        //创建一个数组 
        int[] arr = {2,4,52,2};
        //根据索引找对应的元素 
        int index = 4;
        int element = getElement(arr, index);

        System.out.println(element);
        System.out.println("over");
    }
    /*
     * 根据 索引找到数组中对应的元素
     */
    public static int getElement(int[] arr,int index){ 
        if(arr == null){
            /*
             判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
             这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。 
              */
            throw new NullPointerException("要访问的arr数组不存在");
        }
       	//判断  索引是否越界
        if(index<0 || index>arr.length-1){
             /*
             判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
             这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。 
              */
             throw new ArrayIndexOutOfBoundsException("哥们,角标越界了~~~");
        }
        int element = arr[index];
        return element;
    }
}

注意:如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是将问题返回给该方法的调用者。

那么对于调用者来说,该怎么处理呢?一种是进行捕获处理,另一种就是继续将问题声明出去,使用throws声明处理。

异常的处理机制

如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理。如果异常没有在调用者方法中处理,它继续被抛给这个调用方法的上层方法。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。

捕获异常try…catch

捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。

try{
     编写可能会出现异常的代码
}catch(异常类型1  e){
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}catch(异常类型2  e){
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}catch(异常类型1 | 异常类型2 e){
    //记录日志/打印异常信息/继续抛出异常
}
....

try:捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。建议:此范围尽量小。

try中声明的变量只能在try的语句块内使用 其他位置想要使用必须进行作用域提升

catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常。

  • 可以有多个catch块,按顺序匹配。
  • 如果多个异常类型有包含关系,那么小上大下
  • 可以使用一个catch 捕获多个异常 不能与Exception同时存在

获取异常信息:

捕获到了异常对象,就可以获取异常对象中封装的异常信息,Throwable类中定义了一些方法用于获取异常对象中的信息:

  • public String getMessage():获取异常的描述信息。
  • public void printStackTrace():打印异常的跟踪栈信息并输出到控制台。这些信息包含了异常的类型,异常信息,还包括异常出现的位置,在开发和调试阶段,建议使用printStackTrace。

finally块

finally:在finally代码块中存放的代码都是一定会被执行的。由于异常会引发程序跳转,导致后面有些语句执行不到,如果一定要执行这些语句就可以使用finally,finally常用于释放系统资源。

finally的语法:

 try{
     
 }catch(...){
     
 }finally{
     无论try中是否发生异常,也无论catch是否捕获异常,也不管try和catch中是否有return语句,都一定会执行
 }
 
 或
  try{
     
 }finally{
     无论try中是否发生异常,也不管try中是否有return语句,都一定会执行。
 } 

注意:finally不能单独使用。

当只有在try或者catch中调用退出JVM的相关方法,例如System.exit(0),此时finally才不会执行,否则finally永远会执行。

声明异常throws

throws:用在方法上,表明此方法可能会产生的异常类型。

如果在某方法内通过抛出了必须要处理的编译期异常,有两种选择:要么在当前方法进行捕获处理,要么通过throws在当前方法上进行声明,让方法的调用者去处理。

声明异常格式:

修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{   }	
import java.io.File;
import java.io.FileNotFoundException;

public class TestException {
	public static void main(String[] args) throws FileNotFoundException {
		readFile("不敲代码学会Java秘籍.txt");
	}
	
	// 如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明
	public static void readFile(String filePath) throws FileNotFoundException{
		File file = new File(filePath);
		if(!file.exists()){
			throw new FileNotFoundException(filePath+"文件不存在");
		}
	}
	
}

throw和throws区别

throw 在方法内抛出一个异常对象

throws 在方法的声明处 声明1个或多个异常类型

自定义异常类

(1)要继承一个异常类型 自定义一个编译时异常类型:自定义类继承java.lang.Exception。

​ 自定义一个运行时异常类型:自定义类继承java.lang.RuntimeException。

public class IndexOutOfBoundsException extends RuntimeException{
    //异常信息
    private String message;


    public IndexOutOfBoundsException() {
    }
    //构造函数
    public IndexOutOfBoundsException(String message){
        super(message);
    }
}

(2)建议大家提供至少两个构造器,一个是无参构造,一个是(String message)构造器。

public class IndexOutOfBoundsException extends RuntimeException{
    //异常信息
    private String message;

    public IndexOutOfBoundsException() {
    }
    //构造函数
    public IndexOutOfBoundsException(String message){
        super(message);
    }
}

(3)自定义异常需要提供serialVersionUID

public class IndexOutOfBoundsException extends RuntimeException{
    //异常信息
    private String message;
	static final long serialVersionUID = 23423423435L;

    public IndexOutOfBoundsException() {
    }
    //构造函数
    public IndexOutOfBoundsException(String message){
        super(message);
    }
}

(4)使用自定义异常类

public void setAge(int age) {
        if(age<=0||age>120){
            throw new IndexOutOfBoundsException("超龄了!!!");
     }
        this.age = age;
}
@org.junit.Test
public void test01(){
    UseMyException 蔡徐坤 = new UseMyException("蔡徐坤", 25);
    蔡徐坤.setAge(250);
}

注意点

自定义的异常只能通过throw抛出。

自定义异常最重要的是异常类的名字和message属性。当异常出现时,可以根据名字 判断异常类型。比如:TeamException("成员已满,无法添加");、 TeamException("该员工已是某团队成员");

自定义异常对象只能手动抛出。抛出后由try..catch处理,也可以甩锅throws给调用 者处理。

clone方法和java.lang.Cloneable接口

所有类型都可以重写这个方法,它是获取一个对象的克隆体对象用的,就是造一个和当前对象各种属性值一模一样的对象。当然地址肯定不同。

   1.让要克隆的对象所在的类实现接口Cloneable
   
   2.重写Object clone()
   
   3.让要克隆的对象调用此方法即可
public class CloneTest {
}
class Person implements Cloneable{
    String name;
    int age;
    //重写clone方法因为默认时protected修饰的
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}


/**
test
*/
public class CloneTest {
    @Test
    public void test01() throws CloneNotSupportedException {
        Person person = new Person();
        person.name="cxk";
        System.out.println(person.name);
        //克隆person
        Object clone = person.clone();
       //向下转换
        Person person1 =(Person) clone;

        person1.name="cxk2";
        System.out.println(person1.name);
        System.out.println(person.name);
    }
}

标签:throws,处理,throw,try,int,异常,public
From: https://www.cnblogs.com/21CHS/p/18365583

相关文章

  • 【全网独家】OpenCV C++ 图像处理实战 :多二维码识别(代码+测试部署)
    介绍在现代社会,二维码无处不在,从支付、物流到用户身份验证,二维码的应用极其广泛。本文将详细介绍如何使用OpenCV在C++环境下实现多二维码识别。我们将涵盖其应用场景、原理解释、算法流程图以及实际代码实现。应用使用场景仓储物流管理:快速扫描多个包裹上的二维码,实现高......
  • IDEA弹出JAVA_HOME异常,Markdown插件无法预览
    IDEA异常,theemvironmentvariableJAVA_HOMEdosenotpointtoavalidjvminstalltion.  markdown插件无法预览这个问题困扰了我很久,网上搜了一圈也没得到解决。问题IDEA每当打开新一个项目或是使用某些IDEA插件时就会弹出这个报错的窗口,还关不掉项目正常运行,但是ID......
  • PDF 文件处理PDF合并和拆分工具PDF Merge PDF Splitter for Mac
    “PDFMergePDFSplitterforMac”是一款专门为Mac用户打造的出色PDF文件处理工具。它集合并与拆分PDF文件的核心功能于一体,能极大地方便用户对PDF文档的管理。      软件下载地址在合并功能上,它能迅速将多个PDF文件整合成一个,无论是工作报告、学习资......
  • 深入理解JVM运行时数据区(内存布局 )5大部分 | 异常讨论
    前言:    JVM运行时数据区(内存布局)是Java程序执行时用于存储各种数据的内存区域。这些区域在JVM启动时被创建,并在JVM关闭时销毁。它们的布局和管理方式对Java程序的性能和稳定性有着重要影响。  一、由以下5大部分组成1.Heap堆区(线程共享)概念:堆是JVM中最大......
  • 三层switch转一层switch的处理方法
    阿里三层switch转一层switch的处理方法如下所示的混淆代码,在淘系140、227等滑块的代码经过一些转化后得到。这些转化包括://去自执行避免变量污染traverse(ast,{UnaryExpression:renameScopIdn})//去自执行traverse(ast,{UnaryExpression:movezishixing})//三目运算......
  • Kettle PDI小白新手/进阶/必备 大数据基础之一数据清洗(ETL)基础进阶总结 1.6万字长文
    Kettle是一个开源的数据集成工具,主要用于ETL(抽取、转换、加载)过程。它的全名是PentahoDataIntegration(PDI),而Kettle是其早期的名字,Kettle在2006年被Pentaho收购后,正式更名为PentahoDataIntegration(PDI),因此现在更常被称为PDI。PDI仍然是Pentaho产品套件中的一个重要......
  • 请求处理
    基础概念过滤器(Filter):当有一堆请求,只希望符合预期的请求进来。拦截器(Interceptor):想要干涉预期的请求。监听器(Listener):想要监听这些请求具体做了什么。过滤器过滤敏感词汇(防止sql注入)设置字符编码URL级别的权限访问控制压缩响应信息最常见使用的接口是OncePerRequest......
  • 安装cartopy失败的处理过程,尚在等待中,成功与否不知。
    Win7,Python3.8,sublimetext,运行(build)wind-draw.py提示:ModuleNotFoundError:Nomodulenamed'cartopy'。搜索,在csdn上看到:cartopy安装保姆教程--三天的试错,终于成功了及【Cartopy】安装失败解决方案,一定可行参照安装。查:piplist,发现有pillow,无shapely、pyproj、py......
  • SpringMVC处理请求头、响应头、编码行为
    基本知识http协议中,请求行、请求头部分都是采用的ascii编码,是不支持中文的,若携带不支持的字符,需要使用进行编码,比如常见的urlEncode。而请求体是支持任意编码的,通过Content-Type请求头的charset部分来告知服务端请求体使用何种方式编码。响应行、响应头、响应体亦如是。Content......
  • 《Windows核心编程》:错误处理
    https://www.zhihu.com/people/xiangchun.zeng网络流行的"科学的尽头还是烧开水"这个梗,从发明蒸汽轮机以来,到现在的核电站、核动力航母最终都是通过“烧开水”这种能量转换形式来实现发电和航行。一以贯之,那么可以这么讲:“Windows核心编程的尽头还是调函数”。.NET、MFC、QT、......