/* * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.lang; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOError; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; /** * A collection of static methods that provide convenient access to {@link System#in} * and {@link System#out} for line-oriented input and output. *
* The {@link #readln()} and {@link #readln(String)} methods decode bytes read from * {@code System.in} into characters. The charset used for decoding is specified by the * {@link System##stdin.encoding stdin.encoding} property. If this property is not present, * or if the charset it names cannot be loaded, then UTF-8 is used instead. Decoding * always replaces malformed and unmappable byte sequences with the charset's default * replacement string. *
* Charset decoding is set up upon the first call to one of the {@code readln} methods. * Decoding may buffer additional bytes beyond those that have been decoded to characters * returned to the application. After the first call to one of the {@code readln} methods, * any subsequent use of {@code System.in} results in unspecified behavior. * * @apiNote * The expected use case is that certain applications will use only the {@code readln} * methods to read from the standard input, and they will not mix these calls with * other techniques for reading from {@code System.in}. * * @since 25 */ public final class IO { /* * We are deliberately not including printf, at least not initially, for * the following reasons. First, it introduces a rather cryptic and arcane * formatting language that isn't really suited to beginners. Second, it * is inherently localizable, which drags in a whole bunch of issues about * what locale should be used for formatting, the possible inclusion of * an overload with an explicit Locale parameter, and so forth. These issues * are best avoided for the time being. Third, when string templates come * along, they might offer a better alternative to printf-style formatting, * so it's best not be saddled with this unnecessarily. */ /* * Notes on flushing. We want flushing to occur after every call to println * and print, so that the user can see output immediately. This could be * important if the user calls print() to issue a prompt before calling * readln() instead of the readln(prompt) overload. It's also important to * flush after print() in case the user is relying on print() to emit output * as sort of a progress indicator. * * We rely on System.out to have autoflush enabled, which flushes after every * println() call, so we needn't flush again. We flush unconditionally after * calls to print(). Since System.out is doing a lot of flushing anyway, there * isn't much point trying to make this conditional, for example, only if * stdout is connected to a terminal. */ private IO() { throw new Error("no instances"); } /** * Writes a string representation of the specified object and then writes * a line separator to the standard output. * *
The effect is as if {@link java.io.PrintStream#println(Object) println(obj)} * had been called on {@code System.out}. * * @param obj the object to print, may be {@code null} */ public static void println(Object obj) { System.out.println(obj); } /** * Writes a line separator to the standard output. * *
The effect is as if {@link java.io.PrintStream#println() println()} * had been called on {@code System.out}. */ public static void println() { System.out.println(); } /** * Writes a string representation of the specified object to the * standard output. * *
The effect is as if {@link java.io.PrintStream#print(Object) print(obj)} * had been called on {@code System.out}. * * @param obj the object to print, may be {@code null} */ public static void print(Object obj) { var out = System.out; out.print(obj); out.flush(); } /** * Reads a single line of text from the standard input. *
* One line is read from the decoded input as if by * {@link java.io.BufferedReader#readLine() BufferedReader.readLine()} * and then the result is returned. *
* If necessary, this method first sets up charset decoding, as described in * above in the class specification. * * @return a string containing the line read from the standard input, not * including any line separator characters. Returns {@code null} if an * end of stream has been reached without having read any characters. * * @throws IOError if an I/O error occurs */ public static String readln() { try { return reader().readLine(); } catch (IOException ioe) { throw new IOError(ioe); } } /** * Writes a prompt and then reads a line of input. *
* Writes a prompt as if by calling {@link #print print}, and then reads a single * line of text as if by calling {@link #readln() readln}. *
* If necessary, this method first sets up charset decoding, as described in * above in the class specification. * * @param prompt the prompt string, may be {@code null} * * @return a string containing the line read from the standard input, not * including any line separator characters. Returns {@code null} if an * end of stream has been reached without having read any characters. * * @throws IOError if an I/O error occurs */ public static String readln(String prompt) { print(prompt); return readln(); } /** * The BufferedReader used by readln(). Initialized under a class lock by * the reader() method. All access should be through the reader() method. */ private static BufferedReader br; /** * On the first call, creates an InputStreamReader to decode characters from * System.in, wraps it in a BufferedReader, and returns the BufferedReader. * These objects are cached and returned by subsequent calls. * * @return the internal BufferedReader instance */ static synchronized BufferedReader reader() { if (br == null) { String enc = System.getProperty("stdin.encoding", ""); Charset cs = Charset.forName(enc, StandardCharsets.UTF_8); br = new BufferedReader(new InputStreamReader(System.in, cs)); } return br; } }