• EOFException异常详解


      最近线上的系统被检测出有错误日志,领导让我检查下问题,我就顺便了解了下这个异常。

      了解一个类,当然是先去看他的API,EOFException的API如下:

      通过这个API,我们可以得出以下信息:

    • 这是一个IO异常的子类,名字也是END OF FILE的缩写,当然也表示流的末尾
    • 它在表明一个信息,流已经到末尾了,而大部分做法是以特殊值的形式返回给我们,而不是抛异常

      也就是说这个异常是被主动抛出来的,而不是底层或者编译器返回给我的,就像NullPointerException或IndexOutOfBoundsException一样。

      我们先来看InputStream,这个输入流,当读到了结尾会怎么样,看看API介绍:

      可以看到如果到达流的末尾,那么会返回-1,也就是说我们可以根据这个-1来判断是否到达流的末尾。

      同样的我们看一下输入流的包装类BufferedReader,它有一个读一行的方法:

     

      也可以发现当读到流的末尾,通过返回值null来告诉我们到达流的末尾了,也就是说通过返回一个不可能的值来表示到达流的末尾。

      那我们找一个EOFException的例子,在jdk类中就有一个,那就是ObjectInputStream,我写了一个测试代码,如下:

    复制代码
    package yiwangzhibujian.objectstream;

    import java.io.ByteArrayInputStream;

    import java.io.ByteArrayOutputStream;

    import java.io.ObjectInputStream;

    import java.io.ObjectOutputStream;

    import java.io.Serializable;

    public class ObjectStream {

    public static void main(String[] args) throws Exception {

    User user1
    =new User("yiwangzhibujian",27);

    User user2
    =new User("laizhezhikezhui",24);

    ByteArrayOutputStream bos</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ByteArrayOutputStream();</br>
    ObjectOutputStream oos</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ObjectOutputStream(bos);</br>
    
    oos.writeObject(user1);</br>
    oos.writeObject(user2);</br>
    oos.writeObject(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);</br>
    
    </span><span style="color: #0000ff;">byte</span>[] data =<span style="color: #000000;"> bos.toByteArray();</br>
    ByteArrayInputStream bis</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ByteArrayInputStream(data);</br>
    ObjectInputStream ois</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> ObjectInputStream(bis);</br></br>
    
    System.out.println(ois.readObject());</br>
    System.out.println(ois.readObject());</br>
    System.out.println(ois.readObject());</br>
    System.out.println(ois.readObject());</br>
    

    }

    }

    class User implements Serializable{

    private static final long serialVersionUID = 1L;

    public String name;

    public int age;

    public User(String name, int age) {

    this.name = name;

    this.age = age;

    }

    @Override
    public String toString() {

    return "User [name=" + name + ", age=" + age + "]";

    }

    }

    复制代码

      控制台输出结果为:

    复制代码
    User [name=yiwangzhibujian, age=27]
    User [name=laizhezhikezhui, age=24]
    null
    Exception in thread "main" java.io.EOFException
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:
    2608)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:
    1319)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:
    371)
    at yiwangzhibujian.objectstream.ObjectStream.main(ObjectStream.java:
    28)

    复制代码

      可以感觉到EOFException的用意,因为我们可以往流中放入null值,所以我们没法找到一个不可能的值来表示到达流的末尾,所以只能通过抛异常的方式来告诉用户到达末尾了,相应的抛异常部分的源码如下:

    复制代码
    byte peekByte() throws IOException {
    int val = peek();
    if (val < 0) {
    throw new EOFException();
    }
    return (byte) val;
    }
    复制代码

      也就是说,ObjectInputStream在读取具体的对象之前会优先读取一个标识符,它通过是否能读到符号来判断是否到达流的末尾,因为再底层的流会通过返回-1来表明,然后ObjectInputStream会根据标识符来判断读到的是什么类型,因为ObjectOutputStream 在写入内容的时候会这么做:

      所以说ObjectInputStream可以自己判断流是否到达末尾,但是它无法告诉我们,我们不能替代他们读取这个标记,不然ObjectInputStream将识别不了下一个内容的实际类型。

      所以呢,对于这种异常的一般解决方法就是,捕获,可以记录日志,也可以不做处理,捕获异常以后,把之前读到的数据进行后续的处理就可以了,因为那就是所以的数据。还有就是如果打算记录日志,不要把它的堆栈信息打印出来,容易给人以错觉。毕竟EOFException实质上只是一个消息而已。

      当然抛异常的做法还是有一些偏激,但是当ObjectInputStream在不知道读取对象数量的情况下,确实无法判断是否读完,除非你把之前写入对象流的数量记录下来。所以说出现这个异常时就认真分析一下,这个异常是不是代表一个信息。

      希望我对这个问题的理解,能帮助到遇到同样问题的人。

      

  • 相关阅读:
    Servlet过滤器----Filter
    Servlet监听器详解及举例
    Servlet学习笔记(四)之请求转发与重定向(RequestDispatcher与sendRedirect)
    Servlet学习笔记(二)之Servlet路径映射配置、Servlet接口、ServletConfig、ServletContext
    Servlet学习笔记(三)之HttpServletResponse
    Servlet学习笔记(三)之HttpServletRequest
    Servlet学习笔记(一)之Servlet原理、初始化、生命周期、结构体系
    Python文件(File)及读写操作及生成器yield
    Python学习笔记摘要(一)类型 字符串 函数 列表 深浅拷贝
    Vue如何新建一个项目
  • 原文地址:https://www.cnblogs.com/jpfss/p/8308683.html
Copyright © 2020-2023  润新知