Java异常和注解学习笔记

本文详细介绍了Java中的异常分类,包括检查异常、Error和RuntimeException,以及如何使用try-catch-finally和finally块处理异常。此外,文章还探讨了注解的使用,包括内置注解、自定义注解和元注解的作用。
摘要由CSDN通过智能技术生成

异常

定义:一个需要处理的、不正常的错误(比如比较空指针的值,数组越界之类的)

异常分类

在这里插入图片描述

所有非运行时异常没有统一的父类,叫检查异常只是方便统称,翻译成英文的这个类是没有继承自Exception的,检查异常中包含访问文件,文件末尾读入,类不存在等错误

ErrorRuntimeException属于非检查异常,前者一般是Java虚拟机或内存上(堆栈)的问题,而后者一般是程序编写错误导致的,属于可掌控的异常

图中已经展示了我们一般需要处理的异常是Exception,而RuntimeException又是相对处理更多的

public class Demo01{
    public static void main(String [] args){
        int [] nums = new int [3];
        System.out,println(nums[3]);//RuntimeException,编写时不会报错
    }
}
Class.forName("ex.Demo01");//检查异常

解决异常的方法

如果不知道发生的具体是什么异常,一是执行看报错,二是直接Exception处理,下面给出一般解决异常三种方法

  • try catch finally:类似于if - else if - else的处理方式

    try	catch//捕获异常
    //自己(当前方法)能够处理,使用try catch
    //如果try里执行的代码发生了异常,在发生异常前的语句仍会执行,随后跳转到相应的catch执行
    
    finally 
    //无论正常,还是异常,始终都会执行的代码
    /*
    不论执行完try还是执行完catch,最终都会执行finally的代码
    1.即使在过程中遇到return,也仍然会执行finally
    2.除非虚拟机关闭(System.exit(1)),才不会执行finally里面的语句
    3.finally里一般只写关闭资源的语句,不写IO相关,返回等处理语句,容易出问题,所以在打开资源时通常建议在try里的语句执行完后嵌套一个try-finally语句用于关闭资源
    */
    public static void test03{
        try {
            int[] nums = new  int[3];
            nums[3] = 3;
        }
        catch(NullPointerException e) {
            System.out.println("空指针异常");
        }
        catch(ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界异常");
        }
        catch(Exception e) {//不知道是什么异常时采取的最终手段
            System.out.println("其他异常");
        }
        finally {
            System.out.println("最终执行");
        }
    }
    
    //try with Resources打开资源并自动关闭(常规方法打开两个资源后通常要嵌套两个try-finally语句关闭),类似于try后面写点参数
    try (var in = new Scanner(
    			new FileInputStream("/user/share/dict/words"), StandardCharsets.UTF_8);
         		var out = new PrintWriter("out.txt", StandardCharsets.UTF_8)) {
        while (in.hasNext()) {
            out.println(in.next().toUpperCase());
        }
    }
    //等价于
    try {
        in = new Scanner(new FileInputStream("/user/share/dict/words"), StandardCharsets.UTF_8);
        out = new PrintWriter("out.txt", StandardCharsets.UTF_8);
        while (in.hasNext()) {
            out.println(in.next().toUpperCase());
        }
    }
    finally {
    // 嵌套的try-finally用于关闭资源
        try {          
            if (in != null) {              
                in.close();          
             }      
         }       
         finally {
               if (out != null) {
                      out.close();
                }
           }
    }
    //可以看出上部分的代码相当简洁
    
    //在后期的设计中catch里通常会实现”再抛出“,即将捕获到的异常扔给其他异常,隐藏具体的异常细节
    //如开发中用户使用时出现数据库的异常,可以通过再抛出将数据库的异常隐藏,只给用户显现为后端的异常,用户收到报错后进行反馈,而后端再根据这个异常去修改,找到预先设定好的获取真正异常信息的语句,知道具体的异常信息后进行修改
    try {
        .....
    }
    catch (SQLException original) {//这里是用一个自定义的异常进行处理,将在下面提到
        var e = new ServletException("database error");
        e.initCause(original);
        throw e;//抛出其他异常,隐藏具体的异常
    }
    Throwable original = caughtException.getCause();//获取具体的异常原因
    
  • throws:抛出异常,将异常直接抛给上一级处理,这是极其无脑的做法

    //自己(当前方法)不能够处理,使用throws
    public static void test04() throws NullPointerexception{//抛出异常,抛出给上级,不知道是什么异常也可以写Exception
        Objext obj = null;
        obj.equals("");
    }
    public static void main(String[] args) throws Exception{//继续往上抛出异常给JVM(虚拟机),这是相当消极的做法,通常这一层需要自己写一个try-catch语句处理,而不是扔给JVM当甩手掌柜
        test04();
    }
    
  • throw:自定义异常终止(异常太多,Java自带的异常不够用时用)

    //1.创建类继承Exception,调用super("要提示的异常信息")
    public class MyException extends Exception{//这个继承写啥异常都可以,毕竟异常间有层层的继承关系
        public MyException(String messsage){//自定义异常,在构造器中书写,把发生的具体异常扔给父类处理
            super(message);
        }
    }
    
    //2.使用throw声明一个自定义异常,并且进行try catch或者throws
    //第一种写法
    public class testthrow{
        public static void main(String[] args){
            int age = 188;
            if(age < 0 || age > 120) {
                try{
                    throw new MyException("年龄不能大于120岁或小于0岁");
                }
                catch(MyException e) {//throw向你扔出了异常,这里的catch捕获相应异常
                    e.printStackTrace();//查看异常的所有信息
                    System.out.println(e.getMessage());//查看异常的基本信息
                }
            }
        }
    }
    
    //第二种写法
    public class start {
        public static void main(String[] args) throws Exception{
            int age = 188;
            if(age < 0 || age > 120) {
               throw new MyException("年龄不能大于120岁");
            }
        }
    }
    

常见运行时异常

  1. NullPointerException:当应用程序试图在需要对象的地方使用null时,抛出此异常
  2. IndexOutOfBoundsException:当索引值为负数或大于等于列表大小时,访问列表、数组或字符串时,抛出此异常
  3. ArrayIndexOutOfBoundsException:这是IndexOutOfBoundsException的一个子类,专门用于数组索引越界的情况
  4. ArithmeticException:当出现异常的运算条件时,抛出此异常。例如,整数除零时抛出ArithmeticException的一个子类ArithmeticException("/ by zero")
  5. ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出此异常
  6. IllegalArgumentException:抛出一个表示向方法传递了一个不合法或不适当参数的情况
  7. IllegalStateException:在对象状态不允许进行请求的操作时,抛出此异常
  8. ConcurrentModificationException:当在迭代过程中(例如通过增强型for循环或迭代器)直接修改集合时,抛出此异常
  9. NumberFormatException:当应用程序试图将一个字符串转换成一种数值类型,但该字符串不具有适当的格式时,抛出此异常
  10. UnsupportedOperationException:当不支持请求的操作时,抛出此异常

Annotation注解

地位:和继承类,实现接口一样都是用来增强一个类的功能的,创建时同创建接口和类,关键字是@interface

作用:贴标签(形象化),一般放在要贴标签的类型前

内置(预置)注解

  • @Override用于子类重写父类的方法前,避免拼写导致的错误调用

  • @Deprecated在类的方法前,提示该方法不建议使用(体现为删除线),开发中通常加上该注解,意为过期了下个版本要删除的部分

  • @SuppressWarnings(value = "xxx")忽略警告信息

    xxxunchecked(忽略对泛型的检查),deprecation(不提示过期了),unused(忽略未使用的警告),fallthrough(忽略没有breakswitch case),path(忽略可以对路径的检查),serialversionUID(忽略未被序列化),all(所有)

    @SuppressWarnings(value = "xxx")
    public class Demo01{
        public static void main(String[] args){
            List list = new ArrayList();//有的编译器中未写泛型会有黄色波浪线,这里采用注解可以让其消失
        }
    }
    
  • @SafeVarargs参数安全类型注解,提醒开发者不要用参数做不安全的操作,阻止编译器产生警告

  • @FunctionalInterface函数式接口

自定义注解

一般结合反射使用,在开发框架时会大量用到

下面给出一个自定义注解以及相应测试

@Retention(RetentionPolicy.RUNTIME)//记得注明声明周期,否则无法测试打印,对自定义注解的限制会在元注解部分展示
public @interface MyAnnotation {
    /*
     1.用定义方法的形式,定义一个属性,不能定义方法
     2.方法的名字就是属性的名字,方法的返回值就是属性的类型。
     3.如果想定义属性的默认值,可以用default关键词
     */
     public String value() default "张三"; //String value = "张三";
     public int age() default 22;// int age  = 22;
}

@SuppressWarnings("all")
public class TestMyAnnotation {
    @MyAnnotation(value = "李四", age = 23)//使用自定义注解,如果注解里只有一个属性则可以只写赋值的内容
    @Deprecated//使用没有成员变量的注解时可以不加括号
    public static void Test() throws Exception {
        //用反射获取某个类里的某个方法前的所有注解,检查注解里的值,标签是否正确
        Annotation[] annotations = TestMyAnnotation.class.getMethod("Test").getAnnotations();
        for (Annotation a : annotations) {//判断后强转打印出注解数组里的内容,检查效果
            if (a instanceof MyAnnotation) {
                System.out.println(((MyAnnotation) a).value());
                System.out.println(((MyAnnotation) a).age());
            }
            else {
                System.out.println("@Deprecated");
            }
        }
    }

    public static void main(String[] args) throws Exception {
        //获取多个注解测试
        Test();
        //获取单个注解测试
        //利用反射获取单个注解,通常获取前需要检查是否存在
        boolean hasAnnotation = TestMyAnnotation.class.isAnnotationPresent(SuppressWarnings.class);
        if (hasAnnotation) {
            SuppressWarnings test = TestMyAnnotation.class.getAnnotation(SuppressWarnings.class);
            System.out.println(test.value());//这里因为生命周期是SOURCE而无法显示打印结果
        }
    }
}

元注解

元数据:修饰数据的数据(数据库里的概念)

元注解:修饰注解的注解,可以用来限制自定义注解的使用

  • @Target限制注解使用的位置
public enum ElementType {
    TYPE,//类型,如类,接口,枚举

    FIELD,//属性

    METHOD,//方法

    PARAMETER,//方法参数

    CONSTRUCTOR,//构造方法

    LOCAL_VARIABLE,//本地变量

    ANNOTATION_TYPE,//对一个注解注解

    PACKAGE,//包

    TYPE_PARAMETER,//参数
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})//限制了该注解能放在哪些类型前
public @interface MyAnnotaiton {
    String value() default "张三"; 
    int age() default  22;
}
  • @Retention标明注解的生命周期
public enum RetentionPolicy {
    SOURCE,//只有.java阶段可用,相当于jvm直接丢弃该注解

    CLASS,//java转化未class进行编译时可用

    RUNTIME//编译运行时都可用
}

@Retention(RetentionPolicy.RUNTIME)//限制什么时候能用这个注解
public @interface MyAnnotaiton {
    String value() default "张三"; 
    int age() default  22;
}
  • @Documentjavadoc文件中也包含对注解的声明

默认下javadoc:java帮助文档 ABC.java - >帮助文档中不包含注解的解释

  • @Inherited子类继承父类时同时继承其注解

默认下子类不会继承父类的注解

  • @Repeatable 可重复,一个注解的成员是另一个注解,使用了另一个注解后调用该注解也能实现相应效果,测试使用如下

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Persons {
        Person[] value();//Persons注解的成员是Person注解数组
    }
    
    @Repeatable(Persons.class)//标明后可以声明该注解后调用另一个注解进行使用
    public @interface Person {
        String value() default "";
    }
    
    //标明Person注解
    @Person(value = "artist")
    @Person(value = "coder")
    @Person(value = "PM")
    public class SuperMan {
        public static void main(String[] args) {
            //用反射获取单个注解,也可以不单独用一个变量去记录是否存在
            Persons personsAnnotation = SuperMan.class.getAnnotation(Persons.class);//测试时使用Persons注解
            if (personsAnnotation != null) {
                Person[] persons = personsAnnotation.value();
                for (Person person : persons) {
                    System.out.println("Role: " + person.value());
                }
            }
        }
    }
    

    参考:
    颜群老师的Java课

    最全最详细的Java异常处理机制_1.java异常处理机制 目标:掌握java异常处理机制和常见的java异常处理方法。 (1)-CSDN博客

    java注解-最通俗易懂的讲解_java 注解-CSDN博客

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值