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

  了解一个类,当然是先去看他的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=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos); oos.writeObject(user1);
oos.writeObject(user2);
oos.writeObject(null); byte[] data = bos.toByteArray();
ByteArrayInputStream bis=new ByteArrayInputStream(data);
ObjectInputStream ois=new ObjectInputStream(bis); System.out.println(ois.readObject());
System.out.println(ois.readObject());
System.out.println(ois.readObject());
System.out.println(ois.readObject());
}
}
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在不知道读取对象数量的情况下,确实无法判断是否读完,除非你把之前写入对象流的数量记录下来。所以说出现这个异常时就认真分析一下,这个异常是不是代表一个信息。

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

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

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

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

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

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

代码如下:

  1.  
    package day02;
  2.  
     
  3.  
    import java.io.EOFException;
  4.  
    import java.io.File;
  5.  
    import java.io.FileInputStream;
  6.  
    import java.io.FileNotFoundException;
  7.  
    import java.io.FileOutputStream;
  8.  
    import java.io.IOException;
  9.  
    import java.io.ObjectInputStream;
  10.  
    import java.io.ObjectOutputStream;
  11.  
    import java.util.ArrayList;
  12.  
    import java.util.List;
  13.  
     
  14.  
    /**
  15.  
    *1、创建54张扑克牌,将扑克牌写入文件card.txt
  16.  
    *2、将写入的文件内容,读取出来,可以生成相对应的54张扑克牌
  17.  
    *3、保证扑克牌可以调用自己的方法
  18.  
    */
  19.  
    public class Exercis {
  20.  
    public static void main(String[] args) throws FileNotFoundException, IOException {
  21.  
    ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream(new File("./card.txt")));
  22.  
    List<Card> lists=new ArrayList<Card>();
  23.  
    for(int i=Card.THREE;i<=Card.TWO;i++){
  24.  
    lists.add(new Card(Card.HEITAO,i));
  25.  
    lists.add(new Card(Card.HONGTAO,i));
  26.  
    lists.add(new Card(Card.MEIHUA,i));
  27.  
    lists.add(new Card(Card.FANGKUAI,i));
  28.  
     
  29.  
    }
  30.  
    lists.add(new Card(Card.JOKER,Card.BLACK));
  31.  
    lists.add(new Card(Card.JOKER,Card.COLOR));
  32.  
    for(Card c : lists){
  33.  
    os.writeObject(c);
  34.  
    }
  35.  
    ObjectInputStream is=new ObjectInputStream(new FileInputStream(new File("./card.txt")));
  36.  
    while(true){
  37.  
    Object o = null;
  38.  
    try {
  39.  
    o = is.readObject();
  40.  
    if(o instanceof Card){
  41.  
    System.out.println(o);
  42.  
    }
  43.  
    } catch (ClassNotFoundException e) {
  44.  
    // TODO Auto-generated catch block
  45.  
    e.printStackTrace();
  46.  
    }catch(EOFException e){
  47.  
    System.out.println("读写完毕!");
  48.  
    os.close();
  49.  
    is.close();
  50.  
    break;
  51.  
    }
  52.  
    }
  53.  
    }
  54.  
    }

EOFException异常详解的更多相关文章

  1. 【疑难杂症04】EOFException异常详解

    最近线上的系统被检测出有错误日志,领导让我检查下问题,我就顺便了解了下这个异常. 了解一个类,当然是先去看他的API,EOFException的API如下: 通过这个API,我们可以得出以下信息: 这 ...

  2. JAVA基础——异常详解

    JAVA异常与异常处理详解 一.异常简介 什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错.在java中,阻止当前方法或作用域的情况,称之为异常. java中异常的体系是怎么样的呢? 1 ...

  3. java基础(十五)----- Java 最全异常详解 ——Java高级开发必须懂的

    本文将详解java中的异常和异常处理机制 异常简介 什么是异常? 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常. Java异常的分类和类结构图 1.Java中的所 ...

  4. Java面向对象之异常详解

    目录 Java面向对象之异常[一] Java面向对象之异常[二] 捕获异常的规则 访问异常信息 异常对方法重写的影响 finally详解 Java面向对象之异常[一] Java面向对象之异常[二] 往 ...

  5. cpp异常详解

    1. 异常介绍 在函数在执行过程中如果碰到对错误的处理可以有两种方式, 1. 返回错误,2. 使用异常. 如果作为函数的调用者想要知道具体的错误信息, 就需要维护一套错误列表, 或者用string类型 ...

  6. Java基础 - 异常详解

    异常的层次结构 Throwable Throwable 是 Java 语言中所有错误与异常的超类. Throwable 包含两个子类:Error(错误)和 Exception(异常),它们通常用于指示 ...

  7. java笔记--异常详解与处理

    一.异常概念 Throwable类是Java中所有错误或异常的超类. 1.只有当对象是此类(或其子类)的实例时,才能通过Java虚拟机或着Java throw语句抛出.     2.只有此类或其子类才 ...

  8. c++异常详解

    一.什么是异常处理 一句话:异常处理就是处理程序中的错误. 二.为什么需要异常处理,以及异常处理的基本思想 C++之父Bjarne Stroustrup在<The C++ Programming ...

  9. Java中的异常详解

    一.异常定义 阻止当前方法或作用域继续执行的问题,称为异常 二.异常分析      所有不正常类都继承Throwable类,这个类主要有两个子类Error类和Exception类.Error指系统错误 ...

随机推荐

  1. C++ string中的几个小陷阱,你掉进过吗?

    C++开发的项目难免会用到STL的string,使用管理都比char数组(指针)方便的多,但在得心应手的使用过程中也要警惕几个小陷阱,避免我们项目出bug却迟迟找不到原因. 1.  结构体中的stri ...

  2. CentOS7 下安装 iSCSI Target(tgt) ,使用 Ceph rbd

    目录 一.iSCSI 介绍 1. iSCSI 定义 2. 几种常见的 iSCSI Target 3. 优缺点比较 二.安装步骤 1. 关闭防火墙 2. 关闭selinux 3. 通过 yum 安装 t ...

  3. Java并发编程-synchronized指南

    在多线程程序中,同步修饰符用来控制对临界区代码的访问.其中一种方式是用synchronized关键字来保证代码的线程安全性.在Java中,synchronized修饰的代码块或方法不会被多个线程并发访 ...

  4. 【IT笔试面试题整理】字符串转数组+数组转字符串

    [试题描述]定义一个函数,字符串转数组数组转字符串 [参考代码] public static int strToInt(String str) { int i = 0, num = 0; char[] ...

  5. 字符串匹配的KMP算法-16张图片看明白

    作者: 阮一峰 日期: 2013年5月 1日 字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另 ...

  6. 怎么在XY图表中添加注解(LightningChart控件为例)?

    场景: 折线图上有多个信号,每个信号都需要显示在自己的Y轴上.如何在屏幕的右侧显示每个信号的基本统计值?这里有为每个信号计算基本数据: 最小值,最大值,平均值. | |Signal 3........ ...

  7. (一)java并发知识图谱

  8. Java JDBC的基础知识(五)

    本文主要记录JDBC基础知识之后的部分内容.另外,我看到<Java核心基础2>中第四章是主要介绍数据库编程的.里面有一些说明和应用特别灵活,有些部分也太容易理解,建议大家看一下.这篇是依然 ...

  9. PHP DDos的几个防御方法详解

    这类攻击有一个最大的特性,就是上传流量霎时增大,通常流量高达数十以至近百M,将整台效 劳器,以至将整台机柜的宽带堵住,使网站无法运转,而这样的攻击,我们无法从远程处理,一但那个phpshell运转,你 ...

  10. Java虚拟机 - 结构原理与运行时数据区域

    http://liuwangshu.cn/java/jvm/1-runtime-data-area.html 前言 本来计划要写Android内存优化的,觉得有必要在此之前介绍一下Java虚拟机的相关 ...