Java IO:FilterOutputStream 类

该类和 FilterInputStream 类类似,都是抽象装饰类。

FilterOutputStream 类也位于 java.io 包中,它继承自 OutputStream 类,是一个抽象装饰器类。如下图:

FilterOutputStream 类

从图可以得知,它是很多 InputStream 增强流的基类,其主要用途是为其他输出流添加额外的功能。FilterOutputStream 本身并不直接实现数据的输出操作,而是将具体的输出任务委托给被装饰的输出流,同时在这个过程中可以添加一些额外的处理逻辑,以此来增强输出流的功能。

源码如下:

public class FilterOutputStream extends OutputStream {
    /**
     * 将被过滤的底层输出流
     */
    protected OutputStream out;

    /**
     * 流是否已关闭,默认初始化为 false。
     */
    private volatile boolean closed;

    /**
     * 锁对象,用于防止对 “closed” 实例变量进行竞争
     */
    private final Object closeLock = new Object();

    // 传递被过滤流到内部
    public FilterOutputStream(OutputStream out) {
        this.out = out;
    }

    @Override
    public void write(int b) throws IOException {
        out.write(b);
    }

    @Override
    public void write(byte[] b) throws IOException {
        write(b, 0, b.length);
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
            throw new IndexOutOfBoundsException();

        for (int i = 0 ; i < len ; i++) {
            write(b[off + i]);
        }
    }

    @Override
    public void flush() throws IOException {
        out.flush();
    }

    @Override
    public void close() throws IOException {
        // 该方法将在后续详细介绍
    }
}

通过分析源码,FilterOutputStream 和 FilterInputStream 类一样,将所有请求都委托给了被增强的类,这里是 OutputStream。

但是,FilterOutputStream 类的 close() 方法却是一个列外,该方法代码还不少,如下:

/**
 * 关闭此输出流并释放与该流相关的任何系统资源。
 * 
 * 如果未关闭,FilterOutputStream 的 close() 方法会调用其 flush() 方法刷新流,
 * 然后调用其底层输出流的 close() 方法。
 *
 * @throws     IOException  如果出现 I/O 错误
 * @see        java.io.FilterOutputStream#flush()
 * @see        java.io.FilterOutputStream#out
 */
@Override
public void close() throws IOException {
    // 如果流已经关闭,直接返回
    if (closed) {
        return;
    }

    // 同步处理,设计 closed 为 true,表示已经关闭
    synchronized (closeLock) {
        if (closed) {
            return;
        }
        closed = true;
    }

    Throwable flushException = null; // 存放刷新抛出的异常对象
    try {
        flush(); // 刷新流,避免部分数据在缓存,没有落地
    } catch (Throwable e) {
        flushException = e; // 刷新出现异常
        throw e;
    } finally {
        // 如果刷新没有异常,则调用底层流的 close() 关闭流
        if (flushException == null) {
            out.close();
        } else {
            // 如果刷新存在异常
            try {
                out.close();
            } catch (Throwable closeException) {
               // 评估 flushException 相对于 closeException 的可能优先级
               // 对异常进行合理的合并与抛出,从而保证程序异常处理的准确性和完整性。
               if ((flushException instanceof ThreadDeath) &&
                   !(closeException instanceof ThreadDeath)) {
                   // 将指定的异常附加到为了抛出此异常而被抑制的异常列表中
                   flushException.addSuppressed(closeException);
                   throw (ThreadDeath) flushException;
               }

                if (flushException != closeException) {
                    // 将 flushException 异常添加到 closeException 异常的抑制的异常列表中
                    closeException.addSuppressed(flushException);
                }
                throw closeException;
            }
        }
    }
}

上面代码,重写了 close() 方法,其主要意图是安全且正确地关闭流,同时处理在刷新(flush)和关闭(close)操作中可能出现的异常。

在关闭流时,先确保流没有被重复关闭,然后执行刷新操作将缓冲区数据输出,最后关闭底层流。同时,对刷新和关闭操作中可能出现的异常进行了细致的处理,保证在出现异常时能够保留所有异常信息,便于后续的调试和问题排查。

什么是 ThreadDeath?

ThreadDeath 类位于 java.lang 包中,它继承自 Error 类。在 Java 里,Error 通常代表那些程序无法处理的严重问题。ThreadDeath 用于表示线程因调用 Thread.stop() 方法而被终止的情况。关于该类的更多知识后续将详细介绍。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号