Java 如何找出使用 PrintStream 时发生的异常

How to find out the occurred exception during using a PrintStream in Java

我刚刚读到,在 Java 中,类 PrintStreamPrintWriter 不会抛出已检查的异常。相反,他们使用了一种错误标志,我可以通过调用方法 boolean checkError() (API link).

来读取它

现在,我在问自己如何找出异常发生的原因。有时出现异常的信息可能还不够,或者?

Based on the source code,看起来他们丢弃了异常。所有的 catch 块看起来像这样:

try {
    ...
}
catch (IOException x) {
    trouble = true; // (x is ignored)
}

所以最直接的解决方案可能是尽可能不使用 PrintStream

一种解决方法是扩展 PrintStream 并将输出包装在另一个 OutputStream 中,该 OutputStreamPrintStream 捕获(并丢弃)它之前捕获异常。像这样:

package mcve.util;

import java.io.*;

public class PrintStreamEx extends PrintStream {
    public PrintStreamEx(OutputStream out) {
        super(new HelperOutputStream(out));
    }

    /**
     * @return the last IOException thrown by the output,
     *         or null if there isn't one
     */
    public IOException getLastException() {
        return ((HelperOutputStream) out).lastException;
    }

    @Override
    protected void clearError() {
        super.clearError();
        ((HelperOutputStream) out).setLastException(null);
    }

    private static class HelperOutputStream extends FilterOutputStream {
        private IOException lastException;

        private HelperOutputStream(OutputStream out) {
            super(out);
        }

        private IOException setLastException(IOException e) {
            return (lastException = e);
        }

        @Override
        public void write(int b) throws IOException {
            try {
                super.write(b);
            } catch (IOException e) {
                throw setLastException(e);
            }
        }

        @Override
        public void write(byte[] b) throws IOException {
            try {
                super.write(b);
            } catch (IOException e) {
                throw setLastException(e);
            }
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            try {
                super.write(b, off, len);
            } catch (IOException e) {
                throw setLastException(e);
            }
        }

        @Override
        public void flush() throws IOException {
            try {
                super.flush();
            } catch (IOException e) {
                throw setLastException(e);
            }
        }

        @Override
        public void close() throws IOException {
            try {
                super.close();
            } catch (IOException e) {
                throw setLastException(e);
            }
        }
    }
}