【Java SE】异常

本文介绍了Java中的异常处理机制,包括异常的分类(编译时异常和运行时异常)、异常的处理方式(try-catch-finally,LBYL和EAFP策略)、异常的声明以及如何自定义异常。异常处理是确保程序健壮性的重要手段,通过合理的异常处理,开发者可以更好地控制程序的流程并处理错误情况。
摘要由CSDN通过智能技术生成

目录

什么是异常

 异常的分类

 异常的处理

异常的抛出

异常的声明

异常的处理流程

自定义异常类


什么是异常

异常是指程序在执行过程中发生的不正当行为,是程序发生错误的一种。(常见的异常有:算术异常,数组越界异常,空指针异常等)

java中不同类型的异常都有一个对应的类进行描述,内部维护了一个异常体系结构:

 Throwable 是异常体系的顶层类,其派生出两个重要的子类 , Error 和 Exception
Error 指的是 Java虚拟机JVM 的内部错误、资源耗尽等无法解决的严重问题 (如:StackOverflflowError 和OutOfMemoryError)
 Exception:异常产生后程序员可以通过代码进行处理,使程序继续执行。

 异常的分类

异常根据发生时期的不同可以分为编译时异常和运行时异常

1.编译时异常

在程序编译期间发生的异常,称为编译时异常,也称为受检查异常 (Checked Exception)
public class Person {
    private String name;
    private String gender;
    int age;
    @Override
    public Person clone() {
        return (Person)super.clone();//报错:未处理异常: java.lang.CloneNotSupportedException
    }
}

2.运行时异常

在程序执行期间发生的异常,称为运行时异常,也称为非受检查异常 (Unchecked Exception)
import java.util.Date;
import java.util.Scanner;

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

    //InputMismatchException
    public void test2(){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        System.out.println(n);
    }

    //NumberFormatException
    public void test3(){
        String str = "123";
        int num = Integer.parseInt(str);
    }

    //ClassCastException
    public void test4(){
        Object obj = new Date();
        String str = (String)obj;
    }

    //IndexOutOfBoundsException
    public void test5(){
        //ArrayIndexOutOfBoundsException
		int[] arr = new int[3];
		System.out.println(arr[3]);
        //StringIndexOutOfBoundsException
        String str = "abc";
        System.out.println(str.charAt(3));
    }

    //NullPointerException
    public void test6(){
		int[] arr = null;
		System.out.println(arr[3]);
    }
}
*注:编译时出现的语法性错误,不能称之为异常

 异常的处理

若没有处理异常,异常会交给JVM处理,程序异常终止;若处理了异常,异常则由程序员处理,可以继续执行后续代码。

我们可以通过防御式编程(LBYL或者EAFP)来处理代码中可能出现的异常

1.LBYL: Look Before You Leap.

在操作之前就做充分的检查(通过if-else来处理)

public class Test {
    public int div(int a, int b) {
        if(b == 0) {    //处理b为0时发生的发生算术异常
            return 0;
        }
        return a/b;
    }
}

2.EAFP: It's Easier to Ask Forgiveness than Permission.

先操作, 遇到问题再处理(通过try-catch来处理)

public class Test {
    public static void main(String[] args) {
        try {
            System.out.println(10 / 0);    //可能出现异常的代码
        } catch (ArithmeticException e) {
            e.printStackTrace();    //定为异常的位置
            System.out.println("这里出现了算术异常");   //需要捕获的异常
        }
    }
}

 当然,通过try-catch也可以捕获多个异常:

public class Test {
    public static void main(String[] args) {
        try {
            System.out.println(10 / 0);
        } catch (ArithmeticException | NullPointerException | ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("这里出现了异常");
        }
    }
}

 或:

public class Test {
    public static void main(String[] args) {
        try {
            System.out.println(10 / 0);
        } catch (ArithmeticException e) {
            System.out.println("这里出现了算术异常");
        } catch (NullPointerException e) {
            System.out.println("这里出现了空指针异常");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("这里出现了数组越界异常");
        }
    }
}

try-catch还可以搭配 finally 关键字,finally 中的代码一定会执行的,一般在 finally 中进行一些资源清理的扫尾工作:

public class Test {
    public int test() {
        Scanner sc = null;
        try {
            sc = new Scanner(System.in);
            int data = sc.nextInt();
            return data;
        } catch (InputMismatchException e) {
            e.printStackTrace();
        } finally {
            sc.close();  //一定会执行到
        }
        return 0;
    }
}

*注:

1.try块内抛出异常位置之后的代码将不会被执行

2.catch 进行类型匹配的时候, 不光会匹配相同类型的异常对象, 也会捕捉目标异常类型的子类对象

3.如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到 JVM 收到后中断程序

4.如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误

异常的抛出

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

public class Test {
    public static void test(int a) {
        if (a == 10) {
            throw new ArithmeticException();//抛出一个算术异常
        }
    }
}

那要如何处理主动抛出的异常呢?

如果抛出的是编译时异常,则需要在抛出异常的同时进行处理:

public class Test {
    public static void test2(int a) {
        try {
            if (a == 10) {
                throw new CloneNotSupportedException();//抛出一个编译时异常
            }
        } catch (ArithmeticException e) {
            System.out.println("这里发生了异常");
        }
    }
}

若抛出的是运行时异常,还可以这样子处理:

public class Test {
    public static void test1(int a) {
        if (a == 10) {
            throw new ArithmeticException();
        }
    }
    public static void main(String[] args) {
        try {
            test1(10);
        } catch (ArithmeticException e) {
            System.out.println("这里发生了异常");
        }
    }
}

*注:

1. throw必须写在方法体内部
2. 抛出的对象必须是Exception 或者 Exception 的子类对象
3. 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
5. 异常一旦抛出,其后的代码就不会执行

异常的声明

当我们不想处理该异常时,可以借助throws将异常抛给方法的调用者来处理,即声明当前方法不处理异常,提醒方法的调用者处理异常:

public class Test {
    public static void test1(int a) throws CloneNotSupportedException {
        if (a == 10) {
            throw new CloneNotSupportedException();
        }
    }
}

若抛出的编译时异常有对应的异常声明,则也可以将异常处理交给调用者处理:

public class Test {
    public static void test1(int a) throws CloneNotSupportedException {
        if (a == 10) {
            throw new CloneNotSupportedException();
        }
    }
    public static void main(String[] args) {
        try {
            test1(10);
        } catch (CloneNotSupportedException e) {
            System.out.println("这里发生了异常");
        }
    }
}

方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开:

public class Test {
    public static void test1(int a) throws CloneNotSupportedException,ArithmeticException,NullPointerException {
        if (a == 10) {
            throw new CloneNotSupportedException();
        }
        if (a == 20) {
            throw new ArithmeticException();
        }
        if (a == 30) {
            throw new NullPointerException();
        }
    }
}

当调用声明抛出异常的方法时,我们必须对该异常进行处理:

public class Test {
    public static void test1(int a) throws CloneNotSupportedException {
        if (a == 10) {
            throw new CloneNotSupportedException();
        }
    }
    public static void main(String[] args) {
        try {
            test1(10);
        } catch (CloneNotSupportedException e) {
            System.out.println("这里发生了异常");
        }
    }
}

或者继续使用throws抛出:

public class Test {
    public static void test1(int a) throws CloneNotSupportedException {
        if (a == 10) {
            throw new CloneNotSupportedException();
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        test1(10);
    }
}

*注:

1. throws必须跟在方法的参数列表之后
2. 声明的异常必须是 Exception 或者 Exception 的子类,如果抛出多个异常类型具有父子关系,直接声明父类即可。

异常的处理流程

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

自定义异常类

在java中不仅内置了丰富的异常类,还可以根据实际情况自定义符合实际需求的异常:

class UserNameException extends RuntimeException {
    public UserNameException (String str) {
        super(str);
    }
}
public class Test {
    String userName = "a";
    public void test1(String userName) {
        if (this.userName.equals(userName)) {
            throw new UserNameException("用户名错误");
        }
    }
}

* 注:

1.自定义异常通常会继承自 Exception 或者 RuntimeException
2.继承自 Exception 的异常默认是编译时异常
3.继承自 RuntimeException 的异常默认是运行时异常
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
一、prometheus简介 Prometheus是一个开源的系统监控和告警系统,现在已经加入到CNCF基金会,成为继k8s之后第二个在CNCF维护管理的项目,在kubernetes容器管理系统中,通常会搭配prometheus进行监控,prometheus支持多种exporter采集数据,还支持通过pushgateway进行数据上报,Prometheus再性能上可支撑上万台规模的集群。 二、prometheus架构图 三、prometheus组件介绍 1.Prometheus Server: 用于收集和存储时间序列数据。 2.Client Library: 客户端库,检测应用程序代码,当Prometheus抓取实例的HTTP端点时,客户端库会将所有跟踪的metrics指标的当前状态发送到prometheus server端。 3.Exporters: prometheus支持多种exporter,通过exporter可以采集metrics数据,然后发送到prometheus server端 4.Alertmanager: 从 Prometheus server 端接收到 alerts 后,会进行去重,分组,并路由到相应的接收方,发出报警,常见的接收方式有:电子邮件,微信,钉钉, slack等。 5.Grafana:监控仪表盘 6.pushgateway: 各个目标主机可上报数据到pushgatewy,然后prometheus server统一从pushgateway拉取数据。 四、课程亮点 五、效果图展示 六、讲师简介 先超(lucky):高级运维工程师、资深DevOps工程师,在互联网上市公司拥有多年一线运维经验,主导过亿级pv项目的架构设计和运维工作 主要研究方向: 1.云计算方向:容器 (kubernetes、docker),虚拟化(kvm、Vmware vSphere),微服务(istio),PaaS(openshift),IaaS(openstack)等2.系统/运维方向:linux系统下的常用组件(nginx,tomcat,elasticsearch,zookeeper,kafka等),DevOps(Jenkins+gitlab+sonarqube+nexus+k8s),CI/CD,监控(zabbix、prometheus、falcon)等 七、课程大纲
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

记得开心一点啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值