Javaの System.out.printf() メソッドについて解説します。
System.err.printf() は解説していません。
書式指定子および書式指定文字列の詳細な解説は行っていません。必要に応じて別記事をご参照ください。
記事内のコードは OpenJDK 21 で動作確認済みです。
基本情報
| 種類 | インスタンスメソッド |
| 所属クラス | java.io.PrintStream |
| 修飾子 | public |
| 引数 | 第一引数※1:(書式指定)文字列 第二引数以降※2:すべての参照型 |
| 戻り値 | PrintStream |
| 処理内容 | 引数を書式指定ルールに従って文字列に埋め込み、整形済み文字列を標準出力 out に出力する |
| APIリファレンス | PrintStream (Java SE 21 & JDK 21) |
※1 第一引数の前に Locale インスタンスを取ることも可能
※2 第一引数に通常の文字列を指定した場合は省略可能
基本的な使い方
基本的な構文は次の通りです。
System.out.printf(表示したい書式指定文字列, 値1, 値2, …);
printf() 自体の動作は実にシンプルで、「値を書式付きで表示する」だけです。より具体的には、「書式指定文字列中の書式指定子に、指定した値を適切に埋め込み、出力する」動作となります。
書式指定文字列を利用して整形した文字列を表示する
基本的な printf() の使い方です。
もっとも単純な printf() のコードとその実行結果を次に示します。
public class Main {
public static void main(String[] args) {
System.out.printf("彼は%d歳だ", 10); // 書式指定文字列, 値
}
}彼は10歳だこのとき、printf() は次のように動作します。
- 書式指定文字列を解析し、書式指定子を探す(今回は
%dのみ) %dに 値10を埋め込む- 埋め込み後の文字列、つまり
"彼は10歳だ"を表示する

代表的な書式指定子を次に示します。それぞれ埋め込める値の種類が異なります。
| 書式指定子 | 埋め込める値 |
%s | 文字列※ |
%d | 整数 |
%f | 小数 |
※ 実際にはほぼすべての値を埋め込むことが可能
値が必要ない書式指定子もあります( %n %% など)。
簡単な例を紹介しましたが、これは print("彼は" + "10" + "歳だ") と等価です。printf() である必要性はないように感じられます。
しかし、printf() では、次のように書式指定子にオプションを追加することで、値の表示形式を自由に整形することができます。これが最大の強みです。
public class Main {
public static void main(String[] args) {
// %d に 04 というオプションを追加
// 04 は「値を4桁表示にし、空き領域は0埋めする」ことを表すオプション
System.out.printf("彼は%04d歳だ", 10);
}
}彼は0010歳だこのとき、printf() は次のように動作します。
- 書式指定文字列を解析し、書式指定子を探す
%04dのオプションにしたがって、値10を0010にする%04dに 値0010を埋め込む- 埋め込み後の文字列、つまり
"彼は0010歳だ"を表示する

代表的なオプションを次に示します。書式指定子によって使用できるオプションも異なります。
| オプション | 意味 | 使用できる書式指定子の種類 |
(整数値) | 表示桁(文字)数 | 数値または文字列を扱うもの |
0 | 空き領域を0埋め | 数値を扱うもの |
+ | 符号を強制表示 | 数値を扱うもの |
また、オプションは複数組み合わせることもできます( %04d は (整数値) と 0 の組み合わせ)。
オプションはさらに細かく分類することもできますが、ここでは扱いません。
オプションを使わないと…
先ほどのコードをオプションを用いずに書くと、次のようになります。
public class Main {
public static void main(String[] args) {
int age = 10;
var strAgeLen = String.valueOf(age).length(); // ageの文字列としての長さ
var prefix = strAgeLen >= 4 ? "" : "0".repeat(4 - strAgeLen); // 0埋めの文字列
System.out.printf("彼は" + prefix + "%d歳だ", age);
}
}実行結果は同じですが、明らかにコードが長く、何をしているのか分かりにくくなっています。
オプションを使うことで、複雑な整形プロセスをコードから排し、コードを簡潔に保てます。
printf() には一度に複数の書式指定子と値を指定することもできます。
public class Main {
public static void main(String[] args) {
// %s と %d を同時指定
System.out.printf("彼の名前は%sで、%d歳だ", "ジェームズ", 10);
}
}彼の名前はジェームズで、10歳だこのとき、printf() は次のように動作します。
- 書式指定文字列を解析し、書式指定子を探す(今回は
%sと%dの2つ) %sと%dに値を先頭から順に埋め込む("ジェームズ"は%sに、10は%dに埋め込まれる)- 埋め込み後の文字列、つまり
"彼の名前はジェームズで、10歳だ"を表示する

一括ではなく、先頭から順に埋め込む点に注意しましょう。
普段から「一括か、順番か」を意識する必要はありませんが、知っておくとエラー発生時に「どの書式指定子でエラーが出たのか」を特定しやすくなります。
ここで一度、printf() の動作を再確認しておきましょう。
- 書式指定文字列を解析し、書式指定子を探す
- 書式指定子にオプションがあれば、それに従って値を整形する
- 書式指定子に整形した値を埋め込む
- 2-3を、すべての書式指定子について順に繰り返す
- 埋め込み後の文字列を表示する
printf() を使用しないと…
printf() を使用せずに同じような処理を実現したい場合は、文字列結合を使用します。
しかし、文字列結合にはコードが冗長になる欠点があります。
public class Main {
public static void main(String[] args) {
String name = "真奈美";
String topic = "食べ物";
String target = "スイートコーン";
// 文字列結合の利用
System.out.print(name + "が好きな" + topic + "は" + target + "です");
}
}上のコードは "真奈美が好きな食べ物はスイートコーンです" と表示するものですが、一目見ただけでは何が表示されるのか分かりにくいです。
さらに、文字列結合はその回数が増えるほど処理が遅くなります。オプションも当然使えないため、柔軟な整形もできません。
これらの問題点を踏まえると、printf() は非常に柔軟で便利なことが分かります。
文字列を表示する(非推奨)
例外的に、通常の文字列を渡すことで、その文字列を表示することができます。println() や print() と同じような使い方です。
「通常の文字列」とは、書式指定子を含まない文字列のことです。
public class Main {
public static void main(String[] args) {
System.out.printf("Hello World!\n"); // 通常の文字列
System.out.printf("I'm Java! Nice to meet you!");
}
}Hello World!
I'm Java! Nice to meet you!これは次のコードと等価です。
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
System.out.print("I'm Java! Nice to meet you!");
}
}なお、この使い方では値を指定してもすべて無視されます。書式指定子が含まれない場合、printf() は「値を埋め込む」処理に進まないためです。
public class Main {
public static void main(String[] args) {
// 10, 100, "太郎" はすべて無視される
System.out.printf("Hello World!", 10, 100, "太郎");
}
}Hello World!あくまでも無視するだけで、エラーにはならない点に注意してください。
この使い方では書式指定子を利用しないため、printf() の良さを完全に潰すことになります。さらに、書式指定子が文字列に含まれていなくとも文字列解析は行われるので、println() や print() と比較すると理論上は処理が遅くなります。
以上より、printf() を通常の文字列表示で使用するのは非推奨です。println() や print() で代用しましょう。
応用的な使い方
メソッドチェーンを利用する
この項の理解には、オブジェクト指向プログラミング(OOP)に関する基本的な理解と習熟が必要です。
println() や print() と異なり、System.out.printf() はつねに呼び出し元の PrintStream インスタンスを戻り値として返します。例えば、System.out(初期状態では標準出力)に対して呼び出した場合は、System.out 自身を返します。
呼び出し元の PrintStream インスタンスと戻り値の PrintStream インスタンスは同一(同じインスタンス)です。
これにより、printf() 同士でメソッドチェーンを行えます。
public class Main {
public static void main(String[] args) {
System.out.printf("Hello ")
.printf("World") // メソッドチェーン
.printf("!")
}
}Hello World!これは次のコードと等価です。
public class Main {
public static void main(String[] args) {
System.out.printf("Hello ") // 1命令ずつ記述
System.out.printf("World")
System.out.printf("!")
}
}戻り値が System.out と同一であることは次のコードで確認できます。
import java.io.PrintStream;
public class Main {
public static void main(String[] args) {
PrintStream ps;
ps = System.out.printf("Equal? "); // 戻り値の PrintStream インスタンスを代入
System.out.println(ps == System.out); // ps と System.out が同一かどうか
}
}Equal? true
ただし、メソッドチェーンを使用してもパフォーマンスが向上することはなく、可読性も下がるため、あまり使われません。
printf() のメソッドチェーンは、println() や print() とも組み合わせることができます(これらも PrintStream のインスタンスメソッドであるため)。
ただし、println() と print() には戻り値がないため、それ以上チェーンを繋げることはできません。
よくある間違い
改行の入れ忘れ
printf() は自動で改行しません。そのため、改行したい場合は、\n または %n(推奨)を使用します。
public class Main {
public static void main(String[] args) {
System.out.printf("彼は%&d歳です\n", 20);
System.out.printf("彼は%sが好きです%n", りんご); // 推奨
System.out.print("彼と仲良くしてあげてください");
}
}彼は20歳です
彼はりんごが好きです
彼と仲良くしてあげてください%n が推奨される理由は、OSに合わせた改行コードを出力してくれる(移植性が高い)ためです。
改行コードは、Windowsでは CRLF 、UNIX / Linux / macOSでは LF など、OSによって異なります。
例えば、Linuxで動かしていたJavaプログラムをWindowsに移行する場合、\n では改行コードの違いによる不具合(改行されないなど)が生じる可能性がありますが、%n はそうしたトラブルを未然に防いでくれます。
\n は絶対に避けるべきか
結論から言うと、ほとんどの場面では、\n でも問題になりにくいです。現代のOSや実行環境は、改行コードの違いを吸収してくれるためです。
ただし、文字列をファイルに保存するなど、一部の場面では問題が顕在化することがあります。\n および改行コードの不整合について、詳しくはこちらをご覧ください。
書式指定子と値の数が不一致
書式指定子と値の数が一致していないと、予期しない動作になります。
値が過剰な場合
過剰分の値はすべて無視されます。エラーにはなりません。
public class Main {
public static void main(String[] args) {
System.out.printf("彼は%d歳です", 10, "りんご"); // "りんご" が過剰
}
}彼は10歳です値が不足な場合
エラー MissingFormatArgumentException が発生します。
public class Main {
public static void main(String[] args) {
System.out.printf("彼は%d歳で、%sが好きです", 10); // %s に対応する値が不足
}
}環境によっては「彼は10歳で、」までなら表示されることがあります。ただし、これは保証された動作ではなく、常に表示されるとは限りません。
書式指定子と値の型が不一致
%s %b および値をとらない書式指定子以外の書式指定子には、埋め込める値の型が厳密に定められています。それ以外を埋め込もうとするとエラー IllegalFormatConversionException が発生します。
例えば、%d には整数型しか埋め込めないため、小数型等ではエラーになります。
public class Main {
public static void main(String[] args) {
System.out.printf("%d", 3.14); // 小数型(double)を埋め込もうとしている
}
}代表的な書式指定子が埋め込める型は次の通りです。
| 書式指定子 | 埋め込める値の型 |
%f(小数) | float, double, BigDemical など |
%d(整数) | byte, short, int, long, BigInteger など |
%c(文字) | char, byte, short など |
文字として % を表示する
% を文字として表示したい場合、単に % と記述するだけでは書式指定子の開始構文と解釈され、エラー UnknownFormatConversionException が発生する場合があります。
public class Main {
public static void main(String[] args) {
System.out.printf("%sに5%の塩を加えます", "牛乳");
}
}%の が書式指定子だと誤って解釈されている状態です。これを回避するためには、書式指定子 %% を使用します。
public class Main {
public static void main(String[] args) {
System.out.printf("%sに5%%の塩を加えます", "牛乳");
}
}牛乳に5%の塩を加えます文字列以外を直接表示しようとする
println() や print() とは異なり、printf() では第一引数に(書式指定)文字列以外を渡すことはできません。
public class Main {
public static void main(String[] args) {
System.out.printf(10); // int型の値を直接表示しようとしている
System.out.printf(2.71); // double
System.out.printf('Z'); // char
}
}書式指定子を使用するか、println() や print()で代用しましょう。