MessageFormat
クラスを使用してメッセージをフォーマットする例を示します。
Object[] arguments = { new Integer(7), new Date(), "a disturbance in the Force" }; String result = MessageFormat.format( "At {1,time} on {1,date}, there was {2} on planet " + "{0,number,integer}.", arguments);
複数の引数を配列で渡す必要があることは変わりありませんが、その処理が可変長引数機能が自動化され、ユーザーからは隠されます。さらに、既存のAPIとの上位互換性があります。そのため、たとえばMessageFormat.format
メソッドに、次の宣言が追加されました。
public static String format(String pattern, Object... arguments);
最後の引数の型の後ろに続く3つのピリオドは、最後の引数が配列、つまり一連の引数として渡されることを示しています。可変長引数は、最後の引数の位置でだけ使用できます。MessageFormat.format
に可変長引数宣言が追加されたことで、上記の呼出しは、次のように短くわかりやすい呼出しに置き換えることができます。
String result = MessageFormat.format( "At {1,time} on {1,date}, there was {2} on planet " + "{0,number,integer}.", 7, new Date(), "a disturbance in the Force");
Autoboxingと可変長引数との間には強いシナジーがあります。リフレクションを使用する次のプログラムで示します。
// Simple test framework public class Test { public static void main(String[] args) { int passed = 0; int failed = 0; for (String className : args) { try { Class c = Class.forName(className); c.getMethod("test").invoke(c.newInstance()); passed++; } catch (Exception ex) { System.out.printf("%s failed: %s%n", className, ex); failed++; } } System.out.printf("passed=%d; failed=%d%n", passed, failed); } }
この短いプログラムは、たとえ小さくても、完全なテスト・フレームワークです。コマンド行でクラス名のリストを取ります。クラス名ごとにパラメータなしコンストラクタでクラスをインスタンス化し、testというパラメータなしメソッドを呼び出します。インスタンス化または呼出しが例外をスローした場合、testは失敗したと見なされます。プログラムは問題を出力してから、test結果のサマリーを出力します。リフレクション・ベースのインスタンス化および呼出しで、明示的な配列作成が必要なくなりました。getMethod
メソッドとinvoke
メソッドが可変長引数リストを受け入れるためです。またこのプログラムは、可変長引数を利用する新しいprintf
機能を使用しています。可変長引数を使用しない場合と比べて、プログラムは非常に読みやすくなります。
クライアントの場合は、APIが可変長引数を提供しているときは、必ず利用するべきです。コアAPIでの重要な使用例は、リフレクション、メッセージ・フォーマット、新しいprintf
機能などです。API設計者の場合は、利点がはっきりしている場合にだけ、慎重に使用するべきです。一般的に、可変長引数メソッドはオーバーロードしないようにしてください。オーバーロードすると、プログラマにとっては、どのオーバーロードが呼び出されたのかわかりにくくなるからです。