java eofexception_EOFException异常详解

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

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

90dafc6a2bb64921964a4f8a20ea047c.png

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

这是一个IO异常的子类,名字也是END OF FILE的缩写,当然也表示流的末尾

它在表明一个信息,流已经到末尾了,而大部分做法是以特殊值的形式返回给我们,而不是抛异常

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

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

f2b2f26af777c98aa6c01b3dfaadd281.png

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

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

de361ed31e93b4966f88a576ca900ac1.png

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

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

48304ba5e6f9fe08f3fa1abda7d326ab.png

packageyiwangzhibujian.objectstream;

importjava.io.ByteArrayInputStream;

importjava.io.ByteArrayOutputStream;

importjava.io.ObjectInputStream;

importjava.io.ObjectOutputStream;

importjava.io.Serializable;

public classObjectStream {

public static void main(String[] args) throwsException {

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

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

ByteArrayOutputStream bos=newByteArrayOutputStream();

ObjectOutputStream oos=newObjectOutputStream(bos);

oos.writeObject(user1);

oos.writeObject(user2);

oos.writeObject(null);

byte[] data =bos.toByteArray();

ByteArrayInputStream bis=newByteArrayInputStream(data);

ObjectInputStream ois=newObjectInputStream(bis);

System.out.println(ois.readObject());

System.out.println(ois.readObject());

System.out.println(ois.readObject());

System.out.println(ois.readObject());

}

}

class User implementsSerializable{

private static final long serialVersionUID = 1L;

publicString name;

public intage;

public User(String name, intage) {

this.name =name;

this.age =age;

}

@Override

publicString toString() {

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

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

控制台输出结果为:

48304ba5e6f9fe08f3fa1abda7d326ab.png

User [name=yiwangzhibujian, age=27]

User [name=laizhezhikezhui, age=24]

nullException 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)

48304ba5e6f9fe08f3fa1abda7d326ab.png

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

48304ba5e6f9fe08f3fa1abda7d326ab.png

byte peekByte() throwsIOException {

int val =peek();

if (val < 0) {

throw newEOFException();

}

return (byte) val;

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

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

f8753a0513561a9a5399a2994fb82f53.png

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

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

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

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

需求:  *1、创建54张扑克牌,将扑克牌写入文件card.txt  *2、将写入的文件内容,读取出来,可以生成相对应的54张扑克牌  *3、保证扑克牌可以调用自己的方法

遇到的问题以及解决方法:

1.序列化的问题:你要创建的对象在流中传输,必须将此类对象进行序列化,就是implements Serializable接口

2.EOFException的问题: 你从文件中读取对象的时候,如何判断是否读取完毕。jvm会给抛出EOFException,表示的是,文件中对象读取完毕。所以呢,你在判断是否读取结束的时候,捕获掉这个异常就可以,是捕获不是抛出。

重要的说三次,是捕获,捕获,捕获!

代码如下:

package day02;

import java.io.EOFException;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.util.ArrayList;

import java.util.List;

/**

*1、创建54张扑克牌,将扑克牌写入文件card.txt

*2、将写入的文件内容,读取出来,可以生成相对应的54张扑克牌

*3、保证扑克牌可以调用自己的方法

*/

public class Exercis {

public static void main(String[] args) throws FileNotFoundException, IOException {

ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream(new File("./card.txt")));

List lists=new ArrayList();

for(int i=Card.THREE;i<=Card.TWO;i++){

lists.add(new Card(Card.HEITAO,i));

lists.add(new Card(Card.HONGTAO,i));

lists.add(new Card(Card.MEIHUA,i));

lists.add(new Card(Card.FANGKUAI,i));

}

lists.add(new Card(Card.JOKER,Card.BLACK));

lists.add(new Card(Card.JOKER,Card.COLOR));

for(Card c : lists){

os.writeObject(c);

}

ObjectInputStream is=new ObjectInputStream(new FileInputStream(new File("./card.txt")));

while(true){

Object o = null;

try {

o = is.readObject();

if(o instanceof Card){

System.out.println(o);

}

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}catch(EOFException e){

System.out.println("读写完毕!");

os.close();

is.close();

break;

}

}

}

}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值