— Привіт, Аміго! Сьогодні я розповім, як зробити нову цікаву штуку — підмінити об'єкт 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 = новий 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 = новий PrintStream(outputStream);
 //Встановлюємо його як поточний System.out
 System.setOut(stream);

 //Викликаємо функцію, яка нічого не знає про наші маніпуляції
 printSomething();

 //Перетворюємо записані в наш ByteArray дані в рядок
 String result = outputStream.toString();

 //Повертаємо все як було
 System.setOut(consoleStream);

 // Розгортаємо рядок
 StringBuilder stringBuilder = новий 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!");
}

— Як цікаво. Тепер я починаю потроху розуміти, які великі можливості надають ці маленькі класи.
Дякуємо за цікавий урок, Білаабо.