src/share/classes/java/io/PrintStream.java

Print this page

        

@@ -25,12 +25,13 @@
 
 package java.io;
 
 import java.util.Formatter;
 import java.util.Locale;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
 
-
 /**
  * A <code>PrintStream</code> adds functionality to another output stream,
  * namely the ability to print representations of various data values
  * conveniently.  Two other features are provided as well.  Unlike other output
  * streams, a <code>PrintStream</code> never throws an

@@ -54,11 +55,11 @@
 
 public class PrintStream extends FilterOutputStream
     implements Appendable, Closeable
 {
 
-    private boolean autoFlush = false;
+    private final boolean autoFlush;
     private boolean trouble = false;
     private Formatter formatter;
 
     /**
      * Track both the text- and character-output streams, so that their buffers

@@ -66,43 +67,77 @@
      */
     private BufferedWriter textOut;
     private OutputStreamWriter charOut;
 
     /**
-     * Creates a new print stream.  This stream will not flush automatically.
-     *
-     * @param  out        The output stream to which values and objects will be
-     *                    printed
-     *
-     * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream)
+     * nonNull is explicitly delcared here so as not to create an extra
+     * dependency on java.util.Objects.nonNull. PrintStream is loaded
+     * early during system initialization.
      */
-    public PrintStream(OutputStream out) {
-        this(out, false);
+    private static <T> T nonNull(T obj, String message) {
+        if (obj == null)
+            throw new NullPointerException(message);
+        return obj;
     }
 
-    /* Initialization is factored into a private constructor (note the swapped
-     * parameters so that this one isn't confused with the public one) and a
-     * separate init method so that the following two public constructors can
-     * share code.  We use a separate init method so that the constructor that
-     * takes an encoding will throw an NPE for a null stream before it throws
-     * an UnsupportedEncodingException for an unsupported encoding.
+    /**
+     * Returns the given charset name if it is supported.
+     * @throws NullPointerException          is csn is null
+     * @throws UnsupportedEncodingException  if the charset is not supported
      */
+    private static String verifyCharsetName(String csn)
+            throws UnsupportedEncodingException {
+        nonNull(csn, "charsetName");
+        try {
+            if (Charset.isSupported(csn))
+                return csn;
+        } catch (IllegalCharsetNameException unused) {
+            /* swallow this exception since UnsupportedEncodingException
+             * will be thrown */
+        }
+        throw new UnsupportedEncodingException(csn);
+    }
 
-    private PrintStream(boolean autoFlush, OutputStream out)
-    {
+    /* Private constructors */
+    private PrintStream(boolean autoFlush, OutputStream out) {
         super(out);
-        if (out == null)
-            throw new NullPointerException("Null output stream");
         this.autoFlush = autoFlush;
+        this.charOut = new OutputStreamWriter(this);
+        this.textOut = new BufferedWriter(charOut);
     }
 
-    private void init(OutputStreamWriter osw) {
-        this.charOut = osw;
-        this.textOut = new BufferedWriter(osw);
+    private PrintStream(boolean autoFlush, OutputStream out, String csn)
+            throws UnsupportedEncodingException {
+        super(out);
+        this.autoFlush = autoFlush;
+        this.charOut = new OutputStreamWriter(this, csn);
+        this.textOut = new BufferedWriter(charOut);
     }
 
+    /* Variant of the private constructor so that the given charset name
+     * can be verified before evaluating the OutputStream argument. Used
+     * by constructors creating a FileOutputStream that also take a
+     * charset name.
+     */
+    private PrintStream(boolean autoFlush, String csn, OutputStream out)
+            throws UnsupportedEncodingException {
+        this(autoFlush, out, csn);
+    }
+
     /**
+     * Creates a new print stream.  This stream will not flush automatically.
+     *
+     * @param  out        The output stream to which values and objects will be
+     *                    printed
+     *
+     * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream)
+     */
+    public PrintStream(OutputStream out) {
+        this(out, false);
+    }
+
+    /**
      * Creates a new print stream.
      *
      * @param  out        The output stream to which values and objects will be
      *                    printed
      * @param  autoFlush  A boolean; if true, the output buffer will be flushed

@@ -111,12 +146,11 @@
      *                    character or byte (<code>'\n'</code>) is written
      *
      * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
      */
     public PrintStream(OutputStream out, boolean autoFlush) {
-        this(autoFlush, out);
-        init(new OutputStreamWriter(this));
+        this(autoFlush, nonNull(out, "Null output stream"));
     }
 
     /**
      * Creates a new print stream.
      *

@@ -136,12 +170,16 @@
      * @since  1.4
      */
     public PrintStream(OutputStream out, boolean autoFlush, String encoding)
         throws UnsupportedEncodingException
     {
-        this(autoFlush, out);
-        init(new OutputStreamWriter(this, encoding));
+        /* this(boolean,OutputStream,String) is invoked so that the
+         * OutputStream argument can be validated before the charset name.
+         */
+        this(autoFlush,
+             nonNull(out, "Null output stream"),
+             verifyCharsetName(encoding));
     }
 
     /**
      * Creates a new print stream, without automatic line flushing, with the
      * specified file name.  This convenience constructor creates

@@ -169,11 +207,10 @@
      *
      * @since  1.5
      */
     public PrintStream(String fileName) throws FileNotFoundException {
         this(false, new FileOutputStream(fileName));
-        init(new OutputStreamWriter(this));
     }
 
     /**
      * Creates a new print stream, without automatic line flushing, with the
      * specified file name and charset.  This convenience constructor creates

@@ -208,12 +245,14 @@
      * @since  1.5
      */
     public PrintStream(String fileName, String csn)
         throws FileNotFoundException, UnsupportedEncodingException
     {
-        this(false, new FileOutputStream(fileName));
-        init(new OutputStreamWriter(this, csn));
+        /* this(boolean,String,OutputStream) is invoked so that the 
+         * charset name can be verified before creating an output
+         * stream to the file. */
+        this(false, verifyCharsetName(csn), new FileOutputStream(fileName));
     }
 
     /**
      * Creates a new print stream, without automatic line flushing, with the
      * specified file.  This convenience constructor creates the necessary

@@ -241,11 +280,10 @@
      *
      * @since  1.5
      */
     public PrintStream(File file) throws FileNotFoundException {
         this(false, new FileOutputStream(file));
-        init(new OutputStreamWriter(this));
     }
 
     /**
      * Creates a new print stream, without automatic line flushing, with the
      * specified file and charset.  This convenience constructor creates

@@ -280,12 +318,14 @@
      * @since  1.5
      */
     public PrintStream(File file, String csn)
         throws FileNotFoundException, UnsupportedEncodingException
     {
-        this(false, new FileOutputStream(file));
-        init(new OutputStreamWriter(this, csn));
+        /* this(boolean,String,OutputStream) is invoked so that the
+         * charset name can be verified before creating an output
+         * stream to the file. */
+        this(false, verifyCharsetName(csn), new FileOutputStream(file));
     }
 
     /** Check to make sure that the stream has not been closed */
     private void ensureOpen() throws IOException {
         if (out == null)