zoukankan      html  css  js  c++  java
  • JavaSE学习笔记

    • 程序在执行的过程中出现非正常的情况,最终导致 JVM 非正常停止。异常在 Java 中以类的形式存在,每一个异常类都可以创建对象,在产生异常的时候就是创建了一个异常类的对象,然后将异常对象抛出。
    public class Main {
        public static void main(String[] args) {
            NullPointerException exception = new NullPointerException("空指针异常");
            System.out.println(exception);//java.lang.NullPointerException: 空指针异常
        }
    }
    

    异常继承结构图

    在这里插入图片描述
    编译时异常和运行时异常都发生在运行阶段

    异常的分类

    • 大类参考上面异常继承结构图

    RuntimeException

    • 错误的强制类型转换
    • 空指针异常
    • 数组越界异常
    • 这种异常是可以通过程序检查来避免的

    • 除了 RuntimeException,其余的所有异常都是检查型异常,在编译时期就要对这种异常进行处理,否则编译器就会报错。对这种异常处理有两种方式,一种是使用 throws 异常将异常抛出,抛给调用者,然后调用者也可以选择抛出或者直接处理这个异常,这种方式如果在某一个地方发生了异常,那么程序将终止,不会在继续向下执行。另外一种方式就是使用 try...catch...finally 来处理这个异常,finally 关闭资源以后,程序可以继续向下执行。
    • 在异常发生的时候,如果一直上抛给调用者,那么最终给抛给 main 方法,main 方法继续上抛异常的话,那么这个异常就会抛给 JVM,然后 JVM 就会终止程序的运行。
    • 异常机制可以提高程序的健壮性

    编译时异常

    public class Main {
        public static void main(String[] args) throws ParseException {
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            //date = sdf.parse("2020-1-1 00:00:00");//Wed Jan 01 00:00:00 CST 2020
            date = sdf.parse("2020-1-1");//java.text.ParseException: Unparseable date: "2020-1-1"
            //这里格式不对,所以程序中断抛出异常,程序不再往下进行
            //如果不想让程序中断,那么就可以对这个异常进行捕获处
            System.out.println(date);
        }
    }
    
    //捕获异常
    public class Main {
        public static void main(String[] args) {
            Date date = new Date();
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                date = sdf.parse("2020-1-1");//java.text.ParseException: Unparseable date: "2020-1-1"
            } catch (ParseException e) {
                e.printStackTrace();//java.text.ParseException: Unparseable date: "2020-1-1"
            }
            //这里对异常进行了捕获,所以程序在发生异常的时候并没有中断程序
            System.out.println(date);//Fri Jul 31 15:28:21 CST 2020
        }
    }
    

    运行时异常

    public class Main {
        public static void main(String[] args) {
            String str = "abc";
            System.out.println(str.charAt(3));
            //StringIndexOutOfBoundsException: String index out of range: 3
            //运行时异常要进行捕获处理
            System.out.println(str);
        }
    }
    
    //捕获异常
    public class Main {
        public static void main(String[] args) {
            try {
                System.out.println(3 / 0);
            } catch (Exception e) {
                //java.lang.ArithmeticException: / by zero
                //e.printStackTrace();
                System.out.println(e.getMessage());/// by zero
            }
            System.out.println(3);
        }
    }
    

    异常的产生

    public class Main {
        public static void main(String[] args) throws ParseException {
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            //date = sdf.parse("2020-1-1 00:00:00");//Wed Jan 01 00:00:00 CST 2020
            date = sdf.parse("2020-1-1");//java.text.ParseException: Unparseable date: "2020-1-1"
            //这里格式不对,所以程序中断抛出异常,程序不再往下进行
            //如果不想让程序中断,那么就可以对这个异常进行捕获处
            System.out.println(date);
        }
    }
    
    //parse源码
    public Date parse(String source) throws ParseException {
        ParsePosition pos = new ParsePosition(0);
        Date result = parse(source, pos);
        if (pos.index == 0)
            throw new ParseException("Unparseable date: "" + source + """ ,
               pos.errorIndex);
        return result;
    }
    
    • 通过上面的源码我们可以看出,如果日期的格式不正确那么 JVM 就会检测出来这个异常,此时 JVM 会创建一个异常类对象,这个异常类对象包含了异常产生的原因,位置和内容,使用 throw 手动抛出异常,然后使用红色的字体打印在控制台,然后 JVM 终止当前的程序。

    手动抛出异常

    public class Main {
        public static void main(String[] args) throws ParseException {
            //Exception in thread "main" java.lang.RuntimeException: 除数不能为 0
            //System.out.println(div(1, 0)); //程序中断,往下执行
            try {
                System.out.println(div(1, 0));
            } catch (Exception e) {
                System.out.println(e.getMessage());//除数不能为 0
            }
            System.out.println(div(1, 1));//1
        }
        public static int div(int a, int b) {
            if(b == 0) throw new RuntimeException("除数不能为 0");
            return a / b;
        }
    }
    

    自定义异常类

    public class NullPointerException extends RuntimeException {
        private static final long serialVersionUID = 5162710183389028792L;
    
        /**
         * Constructs a {@code NullPointerException} with no detail message.
         */
        public NullPointerException() {
            super();
        }
    
        /**
         * Constructs a {@code NullPointerException} with the specified
         * detail message.
         *
         * @param   s   the detail message.
         */
        public NullPointerException(String s) {
            super(s);
        }
    }
    
    • Java 中提供的异常类不能够处理所有的异常,通过查看源码,我们可以发现所有的异常类中都有两个方法,这个一无参构造方法,一个是有参构造方法。自定义异常类必须继承 (Exception) 或者 (RuntimeException),如果是发生概率小的异常可以继承 (RuntimeException),表示运行时异常;否则继承 (Exception),编译时异常,在编译阶段就要对异常进行处理。
    public class MyException extends Exception {
        public MyException() {
        }
    
        public MyException(String message) {
            super(message);
        }
    }
    
    public class Main {
        public static void main(String[] args) throws MyException {
            try {
                System.out.println(div(1, 0));
            } catch (Exception e) {
                System.out.println(e.getMessage());//除数不能为 0
            }
            System.out.println(div(1, 0));//自己不处理,抛给虚拟机
            //Exception in thread "main" cn.edu.zut.MyException: 除数不能为 0
        }
    
        public static int div(int a, int b) throws MyException {
            //自定义的异常在使用的时候是要抛给调用者去处理的
            //所以这里不进行处理
            //MyException exception = new MyException("除数不能为 0");
            //if(b == 0) exception;
            if(b == 0) throw new MyException("除数不能为 0");
            return a / b;
        }
    }
    

    在继承机制中,子类的方法抛出的异常不能比父类方法抛出的异常还要多

    final finally finalize

    • final:关键字,最终的,不变的
    • finally:关键字,在异常机制中,必然会执行,在发生异常的时候程序会终止,那么如果使用流的时候可能会打开一些资源,那么这些资源将不会被处理,如果使用 finally,不管程序是否发生异常,程序都会进入 finally 执行程序,此时在 finally 中就可以关闭一些资源,避免空间的浪费。(如果在进入 finally 程序代码块之前退出了 JVM 虚拟机,那么 finally 中的代码将不再执行。)
    • finalize:Object 类中的一个方法,GC 负责调用这个方法进行垃圾回收。
    public class Main {
        public static void main(String[] args) {
            System.out.println(print());//100
        }
        public static int print() {
            int x = 100;
            try {
                return x;
            } finally {
                x ++;
            }
        }
    }
    
    • 我们知道 finally 中的程序一定会被执行,但是 Java 中又规定 Java 方法体中的代码必须自上而下的执行,return 一旦执行,整个方法必须结束。在 IDEA 中我们可以直接查看 .class 文件,然后查看其执行过程。
    public class Main {
        public Main() {
        }
    
        public static void main(String[] args) {
            System.out.println(print());
        }
    
        public static int print() {
            byte x = 100;
    
            byte var1;
            try {
                var1 = x;
            } finally {
                int var5 = x + 1;
            }
    
            return var1;
        }
    }
    
    
  • 相关阅读:
    ubuntu应用商店打不开怎么办
    java线程池系列(1)-ThreadPoolExecutor实现原理
    java并发之SynchronousQueue实现原理
    java并发等待条件的实现原理(Condition)
    轻松掌握java读写锁(ReentrantReadWriteLock)的实现原理
    Java NIO 内存映射文件
    Java NIO Path接口和Files类配合操作文件
    Java 序列化 序列化与单例模式 [ 转载 ]
    Java 序列化 JDK序列化总结
    Java 泛型 Java使用泛型的意义
  • 原文地址:https://www.cnblogs.com/zut-syp/p/13570744.html
Copyright © 2011-2022 走看看