書式化( フォーマット ) の利用

int 型を "100,000,000" や "0001" と、いった具合の書式で String に出力したい場合が結構あると思います。

C / C++ なら printf があるので、フォーマット出力が簡単なんですが Java だと print / println があるのに printf がありません。ですが、java.text パッケージにクラスライブラリが用意されいます。

フォーマットするためのいくつかのクラスを紹介します。本ページのソースコードは Java 1.4.1 のドキュメントを見て Java 1.3.1 でコンパイルテストしました。詳しい使い方は APIドキュメント参照してください。

Package java.text

java.text package の中に文字列をフォーマットするような便利なクラスが入っています。正直 printf にはならないのでちょっと面倒ですが。

パッケージの中身のクラスをちょっとだけ紹介します。

ChoiceFormat 数値範囲を指定するフォーマット
DateFormat 日付・時刻に関係するフォーマット
DecimalFormat 10進数での数値するフォーマット
MessageFormat 汎用的なメッセージのフォーマット
NumberFormat 数値フォーマット
SimpleDateFormat 簡単に日付・時刻のフォーマットを自分で指定できるクラス

Java の場合、用途べつに書式化クラスを分けているようです。

ChoiceFormat

数値の範囲を指定して、範囲条件にあるものチョイスしてくれます。

[File Name] ChoiceFormatTest.java
import java.text.ChoiceFormat;

public class ChoiceFormatTest {
    public static void main(String[] args) {
        double[] limits = {1,2,3,4,5,6,7};
        String[] monthNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
        ChoiceFormat form = new ChoiceFormat(limits, monthNames);
        for (double i = 0.0; i <= 8.0; ++i) {
            System.out.println( i + " -> " + form.format(i) );
        }
    }
}
[出力結果]
0.0 -> Sun
1.0 -> Sun
2.0 -> Mon
3.0 -> Tue
4.0 -> Wed
5.0 -> Thur
6.0 -> Fri
7.0 -> Sat
8.0 -> Sat

上のソースコードは、わかりやすく書いたつもりが、添え字を使って、String を変更する方法と区別がつきませんね。と、いうことで、もう一つ載せておきます。

[File Name] ChoiceFormatTest2.java
import java.text.ChoiceFormat;

public class ChoiceFormatTest2 {
    public static void main(String[] args) {
        double[] limits = {4,12,18};
        String[] aisatu = {"おはよう","こんにちは","こんばんわ"};
        ChoiceFormat form = new ChoiceFormat(limits, aisatu );
        for (double i = 0.0; i <= 8.0; ++i) {
            System.out.println( i + " -> " + form.format(i) );
        }
    }
}
[出力結果]
0.0 時: おはよう
1.0 時: おはよう
2.0 時: おはよう
3.0 時: おはよう
4.0 時: おはよう
5.0 時: おはよう
6.0 時: おはよう
7.0 時: おはよう
8.0 時: おはよう
9.0 時: おはよう
10.0 時: おはよう
11.0 時: おはよう
12.0 時: こんにちは
13.0 時: こんにちは
14.0 時: こんにちは
15.0 時: こんにちは
16.0 時: こんにちは
17.0 時: こんにちは
18.0 時: こんばんわ
19.0 時: こんばんわ
20.0 時: こんばんわ
21.0 時: こんばんわ
22.0 時: こんばんわ
23.0 時: こんばんわ
24.0 時: こんばんわ

と、上のソースコードのように「数値の範囲」をキーとしてメッセージを変えることができます。

# 1.0 時って何時?と、言った具合のいう細かいつっこみはお控えください(^^ゞ

DateFormat

日付のフォーマットで出力します。

[File Name] DateFormatTest.java
import java.text.DateFormat;
import java.util.Date;

public class DateFormatTest {
    public static void main(String[] args) {
    DateFormat fmt = DateFormat.getDateInstance();
    // 現在の時刻を取得
    Date now = new Date();

    String dateString = fmt.format(now);
    System.out.println(dateString);
    }
}
[出力結果]
2003/06/08

本当はロケールを指定した方が良いのですが、指定しないとデフォルトのロケールになります。

Date クラスは時間を格納するクラスです。コンストラクタなしで呼び出すと現在の時間をミリ単位で取得できます。

それと DateFormat.getTimeInstane() で時間を取得することもできます。

上のコードは日本語の環境で動かしたので、 "年/月/日" のような順番になりました。アメリカ版のWindows の場合ではおそらく  06 / 08 / 2003 という具合に "月/日/年" の順番になります。

ようするに、地域(ロケール)によって日付の表記方法が異なるので、日本版とアメリカ版で作り直さなければならない問題が発生します。DateFormat を使うとデフォルトの言語を取得して日本のなら日本の、アメリカのならアメリカの表記方法で出力してくれます。

ただ、上でロケール指定を推奨しているのに、デフォルトで使って良いのか?と、いう問題があります。一番良いのはプロパティファイルを用意してそこの中で言語指定するのがベストでしょうね。面倒ですが。

DecimalFormat

10進数フォーマットという名前ですが、一般的に数値を扱うときは10進数なので一般的な数値フォーマットといった感じのクラスです。特徴としては、出力する数値のフォーマットを細かく指定できます。

[File Name] DateFormatTest.java
import java.text.DecimalFormat;
import java.lang.IllegalArgumentException;

public class DecimalFormatTest {
    public static void main(String[] args) {
        try {
            int data = 123456789;
            DecimalFormat nf = new DecimalFormat("###,###.####");
            System.out.println(nf.toPattern() + " --- " + nf.format(data));
        } catch (IllegalArgumentException iae) {
            System.out.println("IllegalArgumentException");
        }
        try {
            int data = 55;
            DecimalFormat nf = new DecimalFormat("000");
            System.out.println(nf.toPattern() + " --- " + nf.format(data));
        } catch (IllegalArgumentException iae) {
            System.out.println("IllegalArgumentException");
        }
    }
}
[出力結果]
#,##0.#### --- 123,456,789
#000 --- 055

コンストラクタではパターンを指定します。#には0から9までの数字が入るようになります。010の試しに値を使うと、一番左の0のような省略できる0は省略されてしまいます。0を省略したくない場合は # の代わりに 0 を入れると 0 は必ず表示されます。# だけで format( 0 ) にしてしまうと何も表示されないことに気をつけてください。

MessageFormat

メッセージフォーマットという名前で、複雑なフォーマットが可能です。

[File Name] DateFormatTest.java
import java.text.DecimalFormat;
import java.lang.IllegalArgumentException;

public class DecimalFormatTest {
    public static void main(String[] args) {
    Object[] testArgs = {new Long(3), "MyDisk"};

     MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0} file(s).");

    System.out.println(form.format(testArgs));

    }
}
[出力結果]
The disk "MyDisk" contains 3 file(s).

先にデータを保存するためのく配列を作る必要があります。そして書式を指定する文字列では

"The disk \"{1}\" contains {0} file(s)."

と書きます。 すぐに気がつくと思いますが {0}, {1} の部分が Object[] の配列の添え字のオブジェクトに置き換わっています。なので

"{0},{0},{1},{0}"

のように添え字の順番をパターンの方で指定できるので、好きな順番でかまいません。

new Integer(3) のところは java になれていないと int 型を直接入れたくなりますね(^^ゞ。Object のサブクラスしか Object の配列には入らないので気をつけてください。文字列の方は String に置き換わるので new String なんてしなくてもOKです。

おそらく、これが一番 printf の代用として使えると思います。

NumberFormatTest

ロケールの数値フォーマットで出力します。国内ロケールだと3桁でカンマ区切りになるようです。"10000"という数値が "100,000" という具合に表示されます。経理の方で使うのかな、この書式は。

[File Name] DateFormatTest.java
import java.text.NumberFormat;

public class NumberFormatTest {
    public static void main(String[] args) {
    NumberFormat nf = NumberFormat.getInstance();
    System.out.println(nf.format(123456789));
    }
}
[出力結果]
123,456,789

出力結果としては、この表記は場合によっては便利でしょう。ただ、コードのような数値を扱う場合は DecimalFormat の方が良いでしょう。

SimpleDateFormat

DateFormat ではシステムの方に用意されたフォーマットのプリセットを使っていましたが、やっぱり自分の書式で書きたくなります。

[File Name] SimpleDateFormatTest.java
import java.text.SimpleDateFormat;
import java.util.Date;

    public class SimpleDateFormatTest {
        public static void main(String[] args) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
            String dateString = format.format( new Date() );
            System.out.println(dateString);
    }
}
[出力結果]
2003年06月08日

日付を好きなフォーマットで出力できるので結構便利です。

これは最後エンドユーザー向けに出力する時に使う方がいいでしょう。日付のデータを極力 文字列で保存しない方が無難でしょう。もしデータベースなどで文字列を使わなければならない場合は、書式を統一しなければ、いろんな書式方法が乱雑してしまいます。

サーブレットやJSPでこのクラスを使う場合もサイト全体で日付のフォーマットが統一されていないと雑なサイトに思われるので、日付取得メソッドを作り、サイト内では共有するようにするなど配慮した方がいいでしょう。

最後に

最初に上で紹介したクラスのAPIドキュメントを見ると使い方が不明なので、参考にしてくれれば幸いです。