Java异常

1、异常体系 

2、常见异常:

  • java.lang.IllegalAccessError:违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常。
  • java.lang.InstantiationError:实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常.
  • java.lang.OutOfMemoryError:内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
  • java.lang.StackOverflowError:堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出或者陷入死循环时抛出该错误。
  • java.lang.ClassCastException:类造型异常。假设有类A和B(A不是B的父类或子类),O是A的实例,那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。
  • java.lang.ClassNotFoundException:找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
  • java.lang.ArithmeticException:算术条件异常。譬如:整数除零等。
  • java.lang.ArrayIndexOutOfBoundsException:数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
  • java.lang.IndexOutOfBoundsException:索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。
  • java.lang.InstantiationException:实例化异常。当试图通过newInstance()方法创建某个类的实例,而该类是一个抽象类或接口时,抛出该异常。
  • java.lang.NoSuchFieldException:属性不存在异常。当访问某个类的不存在的属性时抛出该异常。
  • java.lang.NoSuchMethodException:方法不存在异常。当访问某个类的不存在的方法时抛出该异常。
  • java.lang.NullPointerException:空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。
  • java.lang.NumberFormatException:数字格式异常。当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。
  • java.lang.StringIndexOutOfBoundsException:字符串索引越界异常。当使用索引值访问某个字符串中的字符,而该索引值小于0或大于等于序列大小时,抛出该异常。

3、非常见异常:

  • java.lang.AbstractMethodError:抽象方法错误。当应用试图调用抽象方法时抛出。
  • java.lang.AssertionError:断言错。用来指示一个断言失败的情况。
  • java.lang.ClassCircularityError:类循环依赖错误。在初始化一个类时,若检测到类之间循环依赖则抛出该异常。
  • java.lang.ClassFormatError:类格式错误。当Java虚拟机试图从一个文件中读取Java类,而检测到该文件的内容不符合类的有效格式时抛出。
  • java.lang.Error:错误。是所有错误的基类,用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况。
  • java.lang.ExceptionInInitializerError:初始化程序错误。当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段。
  • java.lang.IncompatibleClassChangeError:不兼容的类变化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时,抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下,容易引发该错误。
  • java.lang.InternalError:内部错误。用于指示Java虚拟机发生了内部错误。
  • java.lang.LinkageError:链接错误。该错误及其所有子类指示某个类依赖于另外一些类,在该类编译之后,被依赖的类改变了其类定义而没有重新编译所有的类,进而引发错误的情况。
  • java.lang.NoClassDefFoundError:未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误。
  • java.lang.NoSuchFieldError:域不存在错误。当应用试图访问或者修改某类的某个域,而该类的定义中没有该域的定义时抛出该错误。
  • java.lang.NoSuchMethodError:方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。
  • java.lang.ThreadDeath:线程结束。当调用Thread类的stop方法时抛出该错误,用于指示线程结束。
  • java.lang.UnknownError:未知错误。用于指示Java虚拟机发生了未知严重错误的情况。
  • java.lang.UnsatisfiedLinkError:未满足的链接错误。当Java虚拟机未找到某个类的声明为native方法的本机语言定义时抛出。
  • java.lang.UnsupportedClassVersionError:不支持的类版本错误。当Java虚拟机试图从读取某个类文件,但是发现该文件的主、次版本号不被当前Java虚拟机支持的时候,抛出该错误。
  • java.lang.VerifyError:验证错误。当验证器检测到某个类文件中存在内部不兼容或者安全问题时抛出该错误。
  • java.lang.VirtualMachineError:虚拟机错误。用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况。
  • java.lang.ArrayStoreException:数组存储异常。当向数组中存放非数组声明类型对象时抛出。
  • java.lang.CloneNotSupportedException:不支持克隆异常。当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常。
  • java.lang.EnumConstantNotPresentException:枚举常量不存在异常。当应用试图通过名称和枚举类型访问一个枚举对象,但该枚举对象并不包含常量时,抛出该异常。
  • java.lang.Exception:根异常。用以描述应用程序希望捕获的情况。
  • java.lang.IllegalAccessException:违法的访问异常。当应用试图通过反射方式创建某个类的实例、访问该类属性、调用该类方法,而当时又无法访问类的、属性的、方法的或构造方法的定义时抛出该异常。
  • java.lang.IllegalMonitorStateException:违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常。
  • java.lang.IllegalStateException:违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态,而调用了该方法时,抛出该异常。
  • java.lang.IllegalThreadStateException:违法的线程状态异常。当县城尚未处于某个方法的合法调用状态,而调用了该方法时,抛出异常。
  • java.lang.InterruptedException:被中止异常。当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。
  • java.lang.NegativeArraySizeException:数组大小为负值异常。当使用负数大小值创建数组时抛出该异常。
  • java.lang.SecurityException:安全异常。由安全管理器抛出,用于指示违反安全情况的异常。
  • java.lang.TypeNotPresentException:类型不存在异常。

4、异常处理代码应遵守的规范

1、不要大小通吃:不要使用范围大的 Exception 这样的通用异常,去包含掉小的异常类型。如 Thread.sleep() 抛出的 InterruptedException,就不要用 Exception捕获。

因为泛泛的 Exception 之类,恰恰隐藏了我们的目的。另外我们也要保证程序不会捕获到我们不希望捕获的异常。比如,希望 RuntimeException 被扩散出来,而不是被捕获

try {
  // 业务代码
  // …
  Thread.sleep(1000);
} catch (Exception e) {
  //异常处理
}

2、不要生吞:就是假设这里会出现异常,为了图方便,就直接捕获,不做进一步的细节处理了。

如果我们不把异常抛出来,或者也没有输出到日志(Logger)之类,程序可能在后续代码以不可控的方式结束。不能快速定位到具体异常所在。

try {
  // 大量业务代码,假设会发生异常,直接全局捕获了
  // …
  Thread.sleep(1000);
} catch (Exception e) {
  //异常处理
}

3、减少不必要的try catch,且不要用try catch去处理业务逻辑。及业务代码走一套逻辑,发送异常后走另一套逻辑。

Java每实例化一次Exception,都会对当前的栈进行一次快照存储,这是一个相当重的操作,增加了额外的性能开销。

5、try-with-resources 优先于try -finally

传统try catch写法

public static void main(String[] args) {
    FileInputStream inputStream = null;
    try {
        inputStream = new FileInputStream(new File("myFile"));
        System.out.println(inputStream.read());
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }
}

因为在try块和finally块中的代码,都会抛出异常。在这种情况下,第二个异常完全覆盖了第一个异常。调试变得非常复杂。

当Java7引入try-with-resources解决这个问题。

要使用这个构造的资源,必须先实现Autocloseable接口, 其中包含了单个返回void的close方法。如果编写了一个类,它代表的是必须被关闭的资源,那么这个类也应该实现Autocloseable。

public static void main(String[] args) {
    try (FileInputStream inputStream = new FileInputStream(new File("myFile"))) {
        System.out.println(inputStream.read());
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}

将外部资源的句柄对象的创建放在try关键字后面的括号中,当这个try-catch代码块执行完毕后,Java会确保外部资源inputStream 的close方法被调用。

6、try-with-resources实现原理:

异常抑制。将上面的代码反编译后大致逻辑如下:

public static void main(String[] args) {
    try {
        FileInputStream inputStream = new FileInputStream(new File("myFile"));
        Throwable var2 = null;

        try {
            System.out.println(inputStream.read());
        } catch (Throwable var12) {
            var2 = var12;
            throw var12;
        } finally {
            if (inputStream != null) {
                if (var2 != null) {
                    try {
                        inputStream.close();
                    } catch (Throwable var11) {
                   // 这里使用的是异常抑制
                    //关闭资源时遭遇的异常将被“抑制”但不是丢弃,
                    //通过异常的getSuppressed方法,可以提取出被抑制的异常。
                        var2.addSuppressed(var11);
                    }
                } else {
                    inputStream.close();
                }
            }

        }

    } catch (IOException var14) {
        throw new RuntimeException(var14.getMessage(), var14);
    }
}

分别在try,finally中return:

1、不管try,finally都会执行,

2、在try中return,在finally执行前会把结果保存起来,即使在finally中有修改也以try中保存的值为准,

但如果是引用类型,修改的属性会以finally修改后的为准;

3、如果try/finally都有return,直接返回finally中的return

 private static int test1() {
        int i = 1;
        try {
            return i;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            i = 0;
        }
        return i;
    }

    private static int test2() {
        int i = 1;
        try {
            return i;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            i = 0;
            return i;
        }
    }

    private static User test3() {
        User user = new User("u1");
        try {
            return user;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            user = new User("u2");
        }
        return null;
    }

    private static User test4() {
        User user = new User("u1");
        try {
            return user;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            user.setName("u2");
        }
        return null;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值