Java IO 四大附加接口、try-with-resource

@author ixenos

四大附加接口 Closeable、Flushable、Readable、Appendable


Closeable:

  void close() throws IOException 关闭此流并释放与此流关联的所有系统资源

  java.io.closeable扩展了java.lang.AutoCloseable,因此,对任何Closeable进行操作时,都可以使用try-with-resources语句

  • try-with-resources 可以声明一个或多个资源,资源之间用分号隔开。
  •  try (
    java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
    java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
    ) {
    ...
    }

  有关 try-with-resource 特性的具体分析请见下文。

Flushable:

  void flush() 将所有已缓冲输出写入底层流

Readable:

  int read(CharBuffer cb) 形参中的CharBuffer类拥有按顺序随机地进行读写访问的方法,它表示一个内存中的缓冲区或者一个内存映像(虚拟内存)的文件

  

Appendable:

  Appendable append(char c) 添加的单个字符

  Appendable append(CharSequence s) 添加字符序列,CharSequence接口描述了一个char值序列的基本属性,StringCharBufferStringBufferStringBuilder都实现了CharSequence,所以可以传入这些类型的对象

  以上两个方法,都返回this

四大IO抽象类与附加接口的关系


1、InputStream、OutputStream、Reader、Writer都实现了Closeable和AutoCloseable接口,因此,都可以使用 try-with-resources 语句

2、OutputStream、Writer实现了Flushable接口

3、Reader实现了Readable接口

4、Writer实现了Appendable接口

try-with-resource


try-with-resource 是Java SE 7 加入AutoCloseable接口后才有的,closeable接口继承了AutoCloseable接口。

  AutoCloseable接口规定了自动关闭资源:

The close() method of an AutoCloseable object is called automatically when exiting a try-with-resources block for which the object has been declared in the resource specification header.

1、这个所谓的try-with-resources,是个语法糖。实际上就是自动调用资源的close()函数。

 public class TryStudy implements AutoCloseable{
static void test() throws Exception {
try(TryStudy tryStudy = new TryStudy()){
System.out.println(tryStudy);
}
}
@Override
public void close() throws Exception {
}
}

2、可以在一个 try-with-resources 语句中声明一个或多个资源(用分号隔开),但要注意资源的 close 方法调用顺序与它们的创建顺序相反

 try (
java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
)

  资源的close方法在JVM中的调用顺序是: writer.close()   zf.close()

3、下面从编绎器生成的字节码来分析下,try-with-resources到底是怎样工作的:

  TryStudy实现了AutoCloseable接口,下面来看下test函数的字节码:

 static test()V throws java/lang/Exception
TRYCATCHBLOCK L0 L1 L2
TRYCATCHBLOCK L3 L4 L4
L5
LINENUMBER 21 L5
ACONST_NULL
ASTORE 0
ACONST_NULL
ASTORE 1
L3
NEW TryStudy
DUP
INVOKESPECIAL TryStudy.<init> ()V
ASTORE 2
L0
LINENUMBER 22 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L1
LINENUMBER 23 L1
ALOAD 2
IFNULL L6
ALOAD 2
INVOKEVIRTUAL TryStudy.close ()V
GOTO L6
L2
FRAME FULL [java/lang/Throwable java/lang/Throwable TryStudy] [java/lang/Throwable]
ASTORE 0
ALOAD 2
IFNULL L7
ALOAD 2
INVOKEVIRTUAL TryStudy.close ()V
L7
FRAME CHOP 1
ALOAD 0
ATHROW
L4
FRAME SAME1 java/lang/Throwable
ASTORE 1
ALOAD 0
IFNONNULL L8
ALOAD 1
ASTORE 0
GOTO L9
L8
FRAME SAME
ALOAD 0
ALOAD 1
IF_ACMPEQ L9
ALOAD 0
ALOAD 1
INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
L9
FRAME SAME
ALOAD 0
ATHROW
L6
LINENUMBER 24 L6
FRAME CHOP 2
RETURN
LOCALVARIABLE tryStudy LTryStudy; L0 L7 2
MAXSTACK = 2
MAXLOCALS = 3

从字节码里可以看出,的确是有判断tryStudy对象是否为null,如果不是null,则调用close函数进行资源回收。

try-with-resource与异常捕获


1、从 被丢弃 到 被抑制 的异常 Suppressed Exceptions

  再仔细分析,可以发现有一个Throwable.addSuppressed的调用,那么这个调用是什么呢?

  使用了try-catch语句之后(try-with-resource也算是try-catch),有可能会出现两种异常,一个是try块里的异常,一个是调用close函数里抛出的异常。

  a) 在JDK1.7 以前,一旦finally块抛出了close函数里的异常,前面try块catch的异常被丢弃了!

  b) 而在 try-with-resources 语句中如果在调用close函数时出现异常(注意这个前提),那么前面的异常就被称为Suppressed Exceptions,因此Throwable还有个addSuppressed函数可以把它们保存起来,当用户捕捉到close里抛出的异常时,就可以调用Throwable.getSuppressed函数来取出close之前的异常了。

2、注意:

   一个 try-with-resources 语句可以像普通的 try 语句那样有 catch 和 finally 块。

  但是在try-with-resources 语句中, 任意的 catch 或者 finally 块都是在声明的资源被关闭以后才运行。

3、catch多种异常,但抛出一种异常时

  在JDK1.7之前catch多个异常是这样的:

         try{
//逻辑代码
}catch (IOException ex) {
logger.log(ex);
throw new SpecialException();
catch (SQLException ex) {
logger.log(ex);
throw new SpecialException();
}

从上述代码中可以看出这样写非常的难看,并且会出现许多重复的代码。

JDK1.7及以后可以这样:

         try{
//逻辑代码
}catch (IOException | SQLException ex) {
logger.log(ex);
throw new SpecialException();
}

注:上面例子中的ex是隐式的final不可以在catch块中改变ex。

4、在JDK1.7以前的版本,在方法声明中声明抛出的异常如果在方法体内没有抛出时不被允许的,如下:

 static class FirstException extends Exception { 

 }

 static class SecondException extends Exception {

 }

 public void rethrowException(String exceptionName) throws Exception {

   try {

     if (exceptionName.equals("First")) {
//如果异常名称为"First",则抛出异常一
throw new FirstException(); } else {
//否则的话,则抛出异常二
throw new SecondException(); } } catch (Exception e) { throw e;
}
}

JDK1.7及以后版本:

 static class FirstException extends Exception { 

 }

 static class SecondException extends Exception {

 }

 public void rethrowException(String exceptionName) throws Exception, FirstException, SecondException {
try {
// 逻辑代码
}catch (Exception e) { throw e;
}
}

Java IO 四大附加接口、try-with-resource的更多相关文章

  1. 关于SpringMVC项目报错:java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/xxxx.xml]

    关于SpringMVC项目报错:java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/xxxx ...

  2. 出错: IOException parsing XML document from ServletContext resource [/cn.mgy.conig]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/cn.mgy.conig]

    错误的详细内容: 严重: StandardWrapper.Throwable org.springframework.beans.factory.BeanDefinitionStoreExceptio ...

  3. IOException parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/app

    web.xml初始化spring容器出错 org.springframework.beans.factory.BeanDefinitionStoreException: IOException par ...

  4. java.io.Serializable 序列化接口

    什么是序列化.反序列化? Serialization(序列化)是一种将对象以一连串的字节描述的过程: 反序列化deserialization是一种将这些字节重建成一个对象的过程. 序列化通俗一点说就是 ...

  5. Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/dispatcher-servlet.xml]

    这是因为我把 [/WEB-INF/dispatcher-servlet.xml]的位置换成了[config/springmvc/dispatcher-servlet.xml] 因此idea在原来的位置 ...

  6. Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/config/spring/applicationContext.xml]

    在搭建SpringMVC框架的时候遇到了这个问题 问题的原因: 就是没有找到applicatoincontext.xml这个文件, 因为idea自动生成的路径不正确 因此需要再web.xml里面, ( ...

  7. java IO之AutoCloseable,Closeable和Flushable接口

    有3个接口对于流类相当重要.其中两个接口是Closeable和Flushable,它们是在java.io包中定义的,并且是由JDK5添加的.第3个接口是AutoColseable,它是由JDK7添加的 ...

  8. Java中的Serializable接口transient关键字,及字节、字符、对象IO

    1.什么是序列化和反序列化Serialization是一种将对象转为为字节流的过程:deserialization是将字节流恢复为对象的过程. 2.什么情况下需要序列化a)当你想把的内存中的对象保存到 ...

  9. android java.io.IOException: open failed: EBUSY (Device or resource busy)

    今天遇到一个奇怪的问题, 测试在程序的下载界面,下载一个文件第一次下载成功,删除后再下载结果下载报错, 程序:file.createNewFile(); 报错:java.io.IOException: ...

随机推荐

  1. CentOS7配置OpenCV2.4.13

    以管理员身份运行su root输入密码 安装依赖包 yum install gcc gcc-c++ gtk2-devel gimp-devel gimp-devel-tools gimp-help-b ...

  2. Codeforces Round #390 (Div. 2)

    时隔一个月重返coding…… 期末复习了一个月也不亏 倒是都过了…… 就是计组61有点亏 复变68也太低了 其他都还好…… 假期做的第一场cf 三道题 还可以…… 最后room第三 standing ...

  3. 网络爬虫之定向爬虫:爬取当当网2015年图书销售排行榜信息(Crawler)

    做了个爬虫,爬取当当网--2015年图书销售排行榜 TOP500 爬取的基本思想是:通过浏览网页,列出你所想要获取的信息,然后通过浏览网页的源码和检查(这里用的是chrome)来获相关信息的节点,最后 ...

  4. Ansible Filter

    没啥好说的. 自己看吧 http://docs.ansible.com/ansible/playbooks_filters.html

  5. VMware虚拟机服务的vmware-hostd自动启动和停止

    安装了虚拟机 任务管理器会出现vmware-hostd.exe  占用了80端口,导致xampp打不开,所以就想关闭vmware,解决方案如下: 开始——运行——services.msc,找到VM打头 ...

  6. Java获取IP

    public static String getIpAddr(HttpServletRequest request) {        String ip = request.getHeader(&q ...

  7. 使用Image.GetThumbnailImage 方法返回缩略图

    如果 Image 包含一个嵌入式缩略图像,则此方法会检索嵌入式缩略图,并将其缩放为所需大小. 如果 Image 不包含嵌入式缩略图像,此方法会通过缩放主图像创建一个缩略图像. 请求的缩略图像大小为 1 ...

  8. 移动端audio自动播放问题

    中秋临近,心血来潮想做个手机端贺卡,以前接触的移动端较少,虽然是个简单的贺卡,其实也蛮多坑的,简略说一下在制作贺卡的过程遇到的坑: 一:移动端的屏幕大小不能算作body的大小,因为手机浏览器头部都有网 ...

  9. Python学习之旅--第二周--元组、字符串、运算、字典

    一.元组 另一种有序列表叫元组:tuple.tuple和list非常类似,但是tuple一旦初始化就不能修改,比如同样是列出同学的名字: # Author:Tim Gu tuple = (" ...

  10. sql server 查询出的结果集,拼接某一列赋值给一个变量

    现有表Area 如下: SELECT [Areaid] ,[Areaname] ,[Areapid] FROM [Northwind].[dbo].[Area] 查询结果如下图: 需求:用 “-“ ” ...