JavaRush /Курсы /Java Core /Пишем свой ридер-обертку на System.out

Пишем свой ридер-обертку на System.out

Java Core
9 уровень , 7 лекция
Открыта

— Привет, Амиго! Сегодня я расскажу как сделать новую интересную штуку — подменить объект System.out.
System.out — это статическая переменная out типа PrintStream в классе System. Эта переменная имеет модификатор final, так что просто так новое значение ей не присвоить. Но класс System имеет для этого специальный метод setOut(PrintStream stream). Им то мы и воспользуемся.

— Интересно. А на что мы его заменим?

— Нам нужен какой-то объект, куда можно будет собирать выведенные данные. Лучше всего на эту роль подойдет ByteArrayOutputStream. Это специальный класс, который с одной стороны является динамическим (растягиваемым) массивом, а с другой – реализует интерфейс OutputStream.

— Адаптер между массивом и OutputStream?

— Что-то вроде того. Вот как будет выглядеть наш код.

Код
public static void main(String[] args) throws Exception
{
 //запоминаем настоящий PrintStream в специальную переменную
 PrintStream consoleStream = System.out;

 //Создаем динамический массив
 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
 //создаем адаптер к классу PrintStream
 PrintStream stream = new PrintStream(outputStream);
 //Устанавливаем его как текущий System.out
 System.setOut(stream); 

 //Вызываем функцию, которая ничего не знает о наших манипуляциях
 printSomething(); 

 //Преобразовываем записанные в наш ByteArray данные в строку
 String result = outputStream.toString();

 //Возвращаем все как было
 System.setOut(consoleStream);
}

public static void printSomething()
{
 System.out.println("Hi");
 System.out.println("My name is Amigo");
 System.out.println("Bye-bye!");
}

— А что мы будем делать с полученной строкой?

— Да что угодно. Можем, например, развернуть ее задом наперед. Тогда это будет выглядеть так:

Код
public static void main(String[] args) throws Exception
{
 //запоминаем настоящий PrintStream в специальную переменную
 PrintStream consoleStream = System.out;

 //Создаем динамический массив
 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
 //создаем адаптер к классу PrintStream
 PrintStream stream = new PrintStream(outputStream);
 //Устанавливаем его как текущий System.out
 System.setOut(stream); 

 //Вызываем функцию, которая ничего не знает о наших манипуляциях
 printSomething(); 

 //Преобразовываем записанные в наш ByteArray данные в строку
 String result = outputStream.toString();

 //Возвращаем все как было
 System.setOut(consoleStream);

 //разворачиваем строку
 StringBuilder stringBuilder = new StringBuilder(result);
 stringBuilder.reverse();
 String reverseString = stringBuilder.toString();

 //выводим ее в консоль
 System.out.println(reverseString);
}

public static void printSomething()
{
 System.out.println("Hi");
 System.out.println("My name is Amigo");
 System.out.println("Bye-bye!");
}

— Как интересно. Теперь я начинаю понемногу понимать, какие большие возможности дают эти маленькие классы.
Спасибо за интересный урок, Билаабо.

Комментарии (334)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Exaltyr777 Уровень 25
27 октября 2025
//Вызываем функцию, которая ничего не знает о наших манипуляциях Хотелось бы еще пример, где функция "знает" о наших маняпуляциях, чтобы понять разницу.
Anonymous #3585174 Уровень 33
10 сентября 2025
Like
Дмитрий Сергеевич Уровень 22 Expert
16 августа 2025
Вообще не понял эту лекцию. Если есть у нас опытные java-ты напишите простыми словами, что тут делается и зачем. А то запутался с этим адаптером и объменной объекта
I'll kick them all Уровень 5
13 августа 2025
Самое интересное - колдунство в самом классе System:

    public static final PrintStream out = null;
// .....
    public static void setOut(PrintStream out) {
        checkIO();
        setOut0(out);
    }
// ....
    private static native void setOut0(PrintStream out);
1 июля 2025
не корректный комментарий в коде примеров: //создаем адаптер к классу PrintStream нужно: //создаем обертку класса PrintStream ведь wrapper и adapter разные паттерны
Pyramid Head First Уровень 32
30 апреля 2025

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
— не массив, а поток для хранения байтов в памяти.

PrintStream stream = new PrintStream(outputStream);
— это не совсем адаптер, а новый объект PrintStream, который перенаправляет вывод в ByteArrayOutputStream. Комментарии ИИ.
Денис Кокшаров Уровень 32
17 марта 2025
у меня у одного дежавю? это уже было. слово в слово, Билаабо, блааадь
17 июня 2025
То была лекция по подмене System.in, а тут лекция по подмене System.out
Monspiete Уровень 32
27 февраля 2025
Несколько задач по Core можно решить как раз таки только с помощью ByteArrayInputStream/OutputStream, так что берите на вооружение
Mr.Boombastic Уровень 33
13 февраля 2025
Зашел убедиться, что я не один такой...
Danя Уровень 30
28 декабря 2024
можете под коментами сюда написать что за хрень я только что прочитал, поставлю лайк, может кому надо.