7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

System.out.printlnをハックして出力を差し替えてみた

Last updated at Posted at 2026-01-12

はじめに

今回はJavaを勉強したらまず初めに覚えるであろうSystem.out.printlnの出力を変更する方法について紹介します。

そもそも出力を変更って?

そもそもSystem.out.printlnはコンソールに文字列を標準出力するためのメソッドです。
Javaを勉強する際に、プログラムの実行結果を確認する際に利用することが多いと思います。

void main() {
  System.out.println("Hello, World!");
}
実行結果
Hello, World!

実は、printlnメソッドの動作を次のように変更することができます。

  • 標準出力をコンソールではなくファイルに出力する
  • 標準出力の内容を加工してから出力する

System.out.printlnを少しだけ深掘りしてみる

変更の仕方を説明する前に、System.out.printlnを少しだけ深掘りしてみます。

System.out.printlnはJavaの標準ライブラリで提供されているメソッドです。

System.out.println("Hello, World!");

SystemクラスのJavaDocを参考に構造を簡単に説明してみると、

  1. Systemクラスに存在する
  2. out静的フィールドの参照しているPrintStreamオブジェクトの
  3. printlnメソッドを呼び出している

ことになります。

言い換えると、printlnメソッドはPrintStreamクラスに定義されているメソッドです。

Systemクラスの静的フィールドについて

余談ですが、Systemクラスの静的フィールドにはout含めて下記の3つが存在します。

フィールド名 概要
out 標準出力ストリーム(PrintStreamオブジェクト)
err 標準エラーストリーム(PrintStreamオブジェクト)
in 標準入力ストリーム(InputStreamオブジェクト)

errフィールドは標準エラーストリームを表しており、エラーメッセージの出力に利用されます。

void main() {
  System.out.println("Success: Operation completed successfully!");
  System.err.println("Error: Something went wrong!");
}

例として、コマンドプロンプトで実行時、2>を利用して標準エラーストリームの出力先のみをerr.txtに変更しています。

実行結果
>java App 2> err.txt
Success: Operation completed successfully!
>type err.txt
Error: Something went wrong!

inフィールドは標準入力ストリームを表しており、キーボードからの入力を受け取るために利用されます。

void main() {
  @SuppressWarnings("resource")
  Scanner scanner = new Scanner(System.in);
  System.out.print("Enter your name: ");
  String name = scanner.nextLine();
  System.out.println("Hello, " + name + "!");
}

実行結果
Enter your name: Alice
Hello, Alice!

標準出力は差し替えられる

Systemクラスには、setOutというメソッドがあります。

System.setOut(PrintStream out)

このメソッドを使うことで、System.outの参照先(PrintStreamオブジェクト)を変更できます。

PrintStreamオブジェクトは標準出力の動作を定義しているので、PrintStreamオブジェクトを差し替えることで、System.out.printlnの動作を変更できます。

実際に差し替えてみる

では実際に、次の2つの修正を加えたSystem.out.printlnを作成してみます。

  • 標準出力をコンソールではなくsample.txtに出力する
  • printlnメソッドの出力内容の先頭に現在日時を付与する

1.PrintStreamを継承してカスタムクラスを作成する

まずは、PrintStreamクラスを継承してカスタムクラス(今回はPrintStreamWrapper)を作成します。

class PrintStreamWrapper extends PrintStream {
  private static final DateTimeFormatter FORMATTER =
      DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss: ");
  public PrintStreamWrapper(OutputStream out) {
    super(out);
  }
  @Override
  public void println(String x) {
    super.println(now() + x);
  }
  private String now() {
    return LocalDateTime.now().format(FORMATTER);
  }
}

下記のように、カスタムクラスでprintln(String)メソッドをオーバーライドして、出力内容の先頭に現在日時を付与するようにしています。
すべての型の出力を完全に捕捉したい場合は、println(int)println(boolean) などもオーバーライドする必要があります。

  @Override
  public void println(String x) {
    super.println(now() + x);
  }

2. PrintStreamWrapperオブジェクトを生成時にOutputStreamを渡す

次に、1.で作成したPrintStreamWrapperオブジェクトを生成します。
オブジェクト生成時に、標準出力先をsample.txtにするためにFileOutputStreamオブジェクトを渡します。

  // 標準出力先をsample.txtにするためのFileOutputStreamオブジェクト(追記モード)を生成
  FileOutputStream fos = new FileOutputStream("sample.txt", true);
  // PrintStreamWrapperオブジェクトを生成
  PrintStreamWrapper spw = new PrintStreamWrapper(fos);

3. System.setOutでPrintStreamWrapperオブジェクトに差し替える

最後に、System.setOutメソッドでSystem.outの参照先をPrintStreamWrapperオブジェクトに差し替えます。

  System.setOut(spw);

完成コード例

void main() throws FileNotFoundException {
  FileOutputStream fos = new FileOutputStream("sample.txt", true);
  PrintStreamWrapper spw = new PrintStreamWrapper(fos);
  System.setOut(spw);
  // 出力例:2026/01/12 18:17:18: Hello, World!
  System.out.println("Hello, World!");
}

class PrintStreamWrapper extends PrintStream {
  private static final DateTimeFormatter FORMATTER =
      DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss: ");
  public PrintStreamWrapper(OutputStream out) {
    super(out);
  }
  @Override
  public void println(String x) {
    super.println(now() + x);
  }
  private String now() {
    return LocalDateTime.now().format(FORMATTER);
  }
}
sample.txtの出力結果
2026/01/12 18:17:18: Hello, World!

補足:IO.println について

Java25以降では、IO.printlnメソッドが追加されています。
動作としてはSystem.out.printlnと同様に標準出力に文字列を出力します。

IO.printlnの実装を見てみると、Object型の引数を受け取るSystem.out.printlnを呼び出していることがわかります。

    /**
     * Writes a string representation of the specified object and then writes
     * a line separator to the standard output.
     *
     * <p> 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);
    }

そのため、Object型の引数を受け取るSystem.out.printlnメソッドをオーバーライドすることで、IO.printlnの出力内容も変更できます。

void main() throws FileNotFoundException {
  FileOutputStream fos = new FileOutputStream("sample.txt", true);
  PrintStreamWrapper spw = new PrintStreamWrapper(fos);
  System.setOut(spw);
  // 出力例:2026/01/12 18:17:18: Hello, World!
-  System.out.println("Hello, World!");
+  IO.println("Hello, World!");
}

class PrintStreamWrapper extends PrintStream {
  private static final DateTimeFormatter FORMATTER =
      DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss: ");
  public PrintStreamWrapper(OutputStream out) {
    super(out);
  }
  @Override
-  public void println(String x) {
+  public void println(Object x) {  
    super.println(now() + x);
  }
  private String now() {
    return LocalDateTime.now().format(FORMATTER);
  }
}

printlnの動作を変更する場面ある?

自分で記事を書いておいてあれですが、実務で使う場面はあまりないと思います。
そもそも、標準出力を直接利用せず、ログ出力ライブラリを利用することが多いので・・。

ただ、当時自分が2年目ぐらいの時に、おそらく同じようなやり方でprintlnの動作を変えているシステムを見たことはあります。

おわりに

今回はSystem.out.printlnの出力を変更する方法について紹介しました。

Java入門者がオブジェクト指向を理解しはじめたタイミングで本記事を読んでみると、面白いと感じていただけるかなと思っています。

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?