Предопределенные потоки ввода-вывода в Java: System.in, System.out, System.err - Вопросы
Всего: 5 вопросов
1. Что такое предопределенные потоки ввода-вывода в Java: System.in, System.out и System.err?
Что такое предопределенные потоки ввода-вывода в Java: System.in, System.out и System.err?
Это три готовых потока, которые JVM создаёт при запуске программы и хранит в полях public static final класса java.lang.System. Пакет java.lang импортируется автоматически, поэтому потоки доступны без import и без создания объектов.
System.in— стандартный ввод, типInputStream(байтовый поток), дескриптор ОС 0, по умолчанию — клавиатура.System.out— стандартный вывод, типPrintStream, дескриптор 1, по умолчанию — экран терминала.System.err— стандартный поток ошибок, тожеPrintStream, дескриптор 2, по умолчанию — экран терминала.
Связь с терминалом не жёсткая: оболочка может перенаправить любой из потоков в файл (<, >, 2>), а программа — заменить их методами System.setIn(), setOut(), setErr().
2. Чем System.err отличается от System.out и когда его использовать?
Чем System.err отличается от System.out и когда его использовать?
Оба поля — объекты PrintStream с одинаковыми методами (print(), println(), printf()). Разница в канале ОС: System.out пишет в стандартный вывод (дескриптор 1), System.err — в стандартный поток ошибок (дескриптор 2).
- Ошибки можно отделить от полезного вывода: при запуске
java App > out.txtобычный вывод уходит в файл, а сообщенияSystem.errостаются на экране;2> err.txtотправляет ошибки в отдельный файл,> all.txt 2>&1— оба потока в один. - В
System.errпишетe.printStackTrace()без аргументов, поэтому трассировки в IDE подсвечены красным. - Так как это два независимых канала, в консоли IDE строки
outиerrмогут перемешаться; если важен порядок, пишите в один поток.
В реальных приложениях вместо прямой печати в System.err используют логгер (java.util.logging, SLF4J + Logback).
3. Почему System.in.read() на ввод 5 возвращает 53 и как правильно прочитать число с консоли?
Почему System.in.read() на ввод 5 возвращает 53 и как правильно прочитать число с консоли?
System.in — байтовый поток (InputStream). Метод read() возвращает один байт как int от 0 до 255 или -1 в конце ввода. 53 — код символа '5', а следующий вызов вернёт 10 (перевод строки от Enter; в Windows первым придёт 13). Вызов блокирует программу, пока пользователь не нажмёт Enter.
Чтобы прочитать число, читают строку и разбирают её:
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(console.readLine().trim());
InputStreamReaderпереводит байты в символы,BufferedReaderдаётreadLine().- Нечисловой ввод даёт
NumberFormatException; конец ввода (Ctrl+Dв Linux/macOS,Ctrl+Zи Enter в Windows) —readLine()вернётnull. - Обёртку вокруг
System.inне закрывают: вместе с ней закроется самSystem.in, и открыть его заново нельзя.
4. Как перенаправить стандартные потоки из программы с помощью System.setIn(), System.setOut() и System.setErr()?
Как перенаправить стандартные потоки из программы с помощью System.setIn(), System.setOut() и System.setErr()?
Статические методы System.setIn(InputStream), setOut(PrintStream) и setErr(PrintStream) заменяют стандартные потоки: после вызова весь код, который пишет в System.out или читает System.in, работает с новым потоком — файлом или буфером в памяти.
setIn(new ByteArrayInputStream("42\n".getBytes()))подставляет заготовленный ввод в тесте.setOut(new PrintStream(buffer, true))сByteArrayOutputStreamперехватывает вывод метода, который печатает результат вместо возврата.setErr(...)собирает сообщения об ошибках и трассировки в файл журнала.
Поля in, out, err объявлены final, поэтому System.out = ... не компилируется; методы setXxx() меняют их через нативный код JVM. Исходный поток нужно сохранить и вернуть в блоке finally, иначе весь последующий вывод программы и других тестов уйдёт в чужой поток.
5. Почему System.out.println() не выбрасывает IOException и почему он может тормозить программу в больших циклах?
Почему System.out.println() не выбрасывает IOException и почему он может тормозить программу в больших циклах?
Методы PrintStream (print(), println(), printf()) не выбрасывают IOException: ошибка записи только выставляет внутренний флаг. Узнать о сбое можно единственным способом — вызвать checkError(), который сбрасывает буфер и возвращает true, если ошибка была. Поэтому, например, после System.out.close() весь дальнейший вывод молча пропадает.
JVM создаёт System.out с автоматическим сбросом буфера (autoflush): текст появляется в консоли сразу после println(), без flush(). Обратная сторона — каждый вызов обращается к ОС, а методы PrintStream ещё и синхронизированы, так что миллион вызовов println() может занимать секунды. Для большого вывода текст собирают в StringBuilder и печатают один раз или пишут через new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out))) с одним flush() в конце.