Java基础异常处理与输入输出流
Posted 流动的城市
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础异常处理与输入输出流相关的知识,希望对你有一定的参考价值。
finally中的代码执行时机
try语句中含有return,那么finally还会执行吗?如果会,那么是什么时候执行(return前还是return后)
在Java的异常处理中,不论什么情形,finally中的逻辑一定会执行,也就是说try块里面有return,那么finally同样会执行的,执行时机就是try中的return 之前。同时如果try catch以及finally块中都有return ,那么最终执行的return是finaally中的return,前两个没有机会执行。
在正常的流程以及正常的异常处理中,finally保证一定执行,但是特殊情形,比如try块中调用了exit()那么程序就会在try块中强制退出,自然不会执行finally。
另外,逻辑没有进入try而发生异常或者执行退出,那么也不会执行finally语句块。
异常处理原理
异常是在运行时发生的非正常情况或者错误。当程序违反语义规则的时候,JVM就会将其表示为一个异常并抛出,然后被抛出的异常就可以在catch块中进行捕获和处理。
Java中的异常也是对象,并且提供了所有异常的基类java.lang.Throwable。违反语义规则的情形:Java内置的寓意检查,比如空指针异常和数组越界异常;另一种情形就是用户自定义的异常
运行时异常和普通异常
Java中异常类分为错误Error和异常Exception。其父类都是Throwable。Error表示程序出现了严重的错误,并且该错误不可恢复,常常导致程序直接终止,因此程序中不会对此类异常进行捕获(因为Error属于必须解决的异常,是一个正确的程序中所不应该存在的)。
Exception属于是可恢复的异常,可以进行捕获,主要有两种类型:检查异常和运行时异常。 ‘
1. 检查异常:所有继承自Exception的非运行时异常都是检查异常。Java编译器会强制进行捕获此类异常,如IO或者SQL异常。使用场景:a. 异常的发生并不会导致程序的错误,进行处理后可以继续执行后续逻辑,如数据库连接失败并不会退出整个应用; b. 程序依赖了外部的不可靠因素,如网络IO’
2. 运行时异常:编译器没有对此类异常进行强制捕获,如果发生这种异常而代码没有进行捕获的话,会交给JVM进行处理。比如空指针异常,类型转换异常,数组越界异常,数组存储异常,缓冲区异常,算术异常。
使用异常处理的几个原则:
1. Java的异常属于对象,使用了多态的概念,所以如果catch的是父类,那么catch子类的catch块就永远不会执行,所以建议是先捕获子类
2. 尽早抛出异常同时对捕获的异常进行处理
3. 可以根据业务需求自定义异常类
4. 异常能处理就处理,不能处理就抛出。比如对于一些没有很好处理方法的异常,可以直接转型为运行时异常抛给JVM
JavaIO流的实现机制
Java中输入输出都可以看做是流,流可以看做是一组有序字节的集合即数据在设备之间的传输。流的本质是数据的传输,根据吹的数据类型不同,流可以分为两类:字节流和字符流。
字节流是以字节8bit为单位,字符流是以字符16bit为单位。字节流和字符流的主要区别在于字节流在处理输入输出数据的时候不会使用到缓存,而字符流是使用缓存的。字符流继承自Reader和Writer抽象类,字节流继承自InputStream和OutputStream抽象类。 Java的IO设计采用了装饰者模式,使用这种设计模式的好处是可以在运行司动态的给对象添加一些额外的职责,比继承的设计方式更加灵活。
Java的NIO
在非阻塞IO之前(NIO: Nonblocking IO),Java是通过传统的Socket实现基本的网络通信功能。传统的网络通信采用阻塞IO,阻塞IO不仅导致程运行效率低而且在多线程环境下还会导致大量的进程上下文切换。在1.4时引入了非阻塞IO,NIO通过Selector Channel和Buffer来实现非阻塞IO操作。
NIO实现上使用的是Reactor设计模式,可以处理多个事件源。
Java的序列化
Java中提供两种对象持久化方式,序列化和外部序列化。
序列化:序列化是指将对象以一串字节进行描述的过程,序列化可以将对象的状态写在流里面进行网络传输,或者保存到文件或数据库中,在需要的时候可以反序列化出对象。在需要进行序列化的类中实现Serializable接口。
序列化的特点:
1. 如果一个类可以被序列化,那么其子类也是可以序列化的
2. static类型的数据属于类,transient类型的数据属于临时数据,因此被声明为这两种类型的数据 是不可以进行序列化的。
序列化使用场景(使用序列化会影响系统的性能,所以尽可能不用):
1. 需要将对象通过网络来发送或者持久化到文件或者数据库中
2. 序列化可以实现深复制-也就是通过序列化来构建一个对象
反序列化:将流转化为对象
序列化和反序列化的时候,每一个类都有一个serialVersioUID,在反序列化的过程中通过serialVersioUID来判断类的兼容性,如果待序列化的对象和目标对象的serialVersioUID不同,那么就会抛出InvalidClassException,因此为了使序列化和反序列化正常进行,强烈建议在对需要进行序列化的类中显式的声明static final修饰的serialVersioUID,作用在于:
1. 提高程序运行效率,因为如果不显式的提供,那么程序会需要计算得到该serialVersioUID
2. 提高程序的兼容性,因为不同平台计算serialVersioUID的方式可能不一样
3. 增强版本间的兼容性,如果不显示提供,那么类在修改之后,可能导致新版本的类的serialVersioUID与之前不一样,而使得序列化失败
外部序列化:Externalizable
外部序列化与内部序列化的去呗在于序列化是内置的API,只需要实现Serializable接口即可,开发人员不需要再额外的写序列化逻辑就可以实现对象的序列化。而外部序列化Externalizable接口中提供的两个读写函数必须要开发人员来实现,因此比较复杂,但是优点是比较灵活,对需要持久化的对象可以按需序列化,相应的效率也搞一些。
以上是关于Java基础异常处理与输入输出流的主要内容,如果未能解决你的问题,请参考以下文章