JDK-8342937 : Enhance java.io.IO with parameter-less println() and readln()
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.io
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 24
  • Submitted: 2024-10-24
  • Updated: 2025-04-08
  • Resolved: 2024-10-31
Related Reports
CSR :  
Relates :  
Description
Summary
-------

Several new methods, namely `println()` and `readln()` are added to `java.io.IO`, and corresponding supporting classes.

Problem
-------

Currently the `java.io.IO` class provides two output methods: `print(Object)` and `println(Object)`. But, if the caller used the `print(Object)` method, and now needs to issue a newline, it is inconvenient to use `println("")`.

For input `java.io.IO` only provides `readln(String)`, which emits a prompt. Sometimes, it may be desirable to read a line from the input without a prompt.

Solution
--------

`println()` is added to `java.io.IO`, which emits the newline. A corresponding method is added to `java.io.Console`, to preserve the invariant that every method in `java.io.IO` only delegates to a same-named method in `java.io.Console`.

`readln()` is added to `java.io.IO`, which reads a line, without printing a prompt. Corresponding method is added to `java.io.Console` and `jdk.jshell.JShellConsole`.

All these newly added methods with be marked as preview API.

Specification
-------------

The exact proposal is this:

    diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java
    index 0aa12bdf4c8b5..6d7e1694d1230 100644
    --- a/src/java.base/share/classes/java/io/Console.java
    +++ b/src/java.base/share/classes/java/io/Console.java
    @@ -172,6 +172,19 @@ public Console println(Object obj) {
             throw newUnsupportedOperationException();
         }

    +    /**
    +     * Terminates the current line in this console's output stream using
    +     * {@link System#lineSeparator()} and then flushes the console.
    +     *
    +     * @return  This console
    +     *
    +     * @since 24
    +     */
    +    @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES)
    +    public Console println() {
    +        return println("");
    +    }
    +
         /**
          * Writes a string representation of the specified object to this console's
          * output stream and then flushes the console.
    @@ -214,6 +227,24 @@ public String readln(String prompt) {
             throw newUnsupportedOperationException();
         }

    +    /**
    +     * Reads a single line of text from this console.
    +     *
    +     * @throws IOError
    +     *         If an I/O error occurs.
    +     *
    +     * @return  A string containing the line read from the console, not
    +     *          including any line-termination characters, or {@code null}
    +     *          if an end of stream has been reached without having read
    +     *          any characters.
    +     *
    +     * @since 24
    +     */
    +    @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES)
    +    public String readln() {
    +        throw newUnsupportedOperationException();
    +    }
    +
         /**
          * Writes a formatted string to this console's output stream using
          * the specified format string and arguments with the
    diff --git a/src/java.base/share/classes/java/io/IO.java b/src/java.base/share/classes/java/io/IO.java
    index 7485f87f03fda..a49a51041fc04 100644
    --- a/src/java.base/share/classes/java/io/IO.java
    +++ b/src/java.base/share/classes/java/io/IO.java
    @@ -63,6 +63,21 @@ public static void println(Object obj) {
             con().println(obj);
         }

    +    /**
    +     * Terminates the current line on the system console and then flushes
    +     * that console.
    +     *
    +     * <p> The effect is as if {@link Console#println() println()}
    +     * had been called on {@code System.console()}.
    +     *
    +     * @throws IOError if {@code System.console()} returns {@code null},
    +     *                 or if an I/O error occurs
    +     * @since 24
    +     */
    +    public static void println() {
    +        con().println();
    +    }
    +
         /**
          * Writes a string representation of the specified object to the system
          * console and then flushes that console.
    @@ -99,6 +114,24 @@ public static String readln(String prompt) {
             return con().readln(prompt);
         }

    +    /**
    +     * Reads a single line of text from the system console.
    +     *
    +     * <p> The effect is as if {@link Console#readln() readln()}
    +     * had been called on {@code System.console()}.
    +     *
    +     * @return a string containing the line read from the system console, not
    +     * including any line-termination characters. Returns {@code null} if an
    +     * end of stream has been reached without having read any characters.
    +     *
    +     * @throws IOError if {@code System.console()} returns {@code null},
    +     *                 or if an I/O error occurs
    +     * @since 24
    +     */
    +    public static String readln() {
    +        return con().readln();
    +    }
    +
         private static Console con() {
             var con = System.console();
             if (con != null) {
    diff --git a/src/jdk.jshell/share/classes/jdk/jshell/JShellConsole.java b/src/jdk.jshell/share/classes/jdk/jshell/JShellConsole.java
    index fe73d6965cb97..014766f9ff7c4 100644
    --- a/src/jdk.jshell/share/classes/jdk/jshell/JShellConsole.java
    +++ b/src/jdk.jshell/share/classes/jdk/jshell/JShellConsole.java
    @@ -28,6 +28,7 @@
     import java.io.PrintWriter;
     import java.io.Reader;
     import java.nio.charset.Charset;
    +import jdk.internal.javac.PreviewFeature;

     /**
      * An interface providing functionality for {@link java.io.Console} in the user's snippet.
    @@ -75,6 +76,21 @@ public interface JShellConsole {
          */
         public String readLine(String prompt) throws IOError;

    +    /**
    +     * Reads a single line of text from the console.
    +     *
    +     * @throws IOError
    +     *         If an I/O error occurs.
    +     *
    +     * @return  A string containing the line read from the console, not
    +     *          including any line-termination characters, or {@code null}
    +     *          if an end of stream has been reached.
    +     * @see java.io.Console#readLine()
    +     * @since 24
    +     */
    +    @PreviewFeature(feature=PreviewFeature.Feature.IMPLICIT_CLASSES)
    +    public String readLine() throws IOError;
    +
         /**
          * Provides a prompt, then reads a password or passphrase from
          * the console with echoing disabled.

Comments
Moving to Approved.
31-10-2024

> Presumably the text for the no-arg readln() method: > > + * Writes a prompt as if by calling {@code print}, then reads a single line > + * of text from this console. > > should be updated to omit the "Writes a prompt" portion. Correct, sorry for that. Updated both here and in the corresponding PR. Thanks!
25-10-2024

Moving to Provisional, not Approved. Presumably the text for the no-arg readln() method: + * Writes a prompt as if by calling {@code print}, then reads a single line + * of text from this console. should be updated to omit the "Writes a prompt" portion.
25-10-2024

At this stage, it is, in my opinion, better to keep the methods under the Simple Source Files JEP, and in the preview mode.
24-10-2024

From the peanut gallery: The no-arg println() is a great addition for parity with System.out.println(). The existing disparity between System.out and Console was already a problem, just a much smaller one because we've never expected much mass migration or regular context-switching between those. Still, good to handle it too at the same time. The no-arg readln() is, imho, a good addition too, because readln("") feels unnatural and forced when you simply have no need to display a prompt. I would question whether the Console methods should really be preview features; it *independently* makes sense to add them no matter what happens with the JEP.
24-10-2024