今月から,java.lang,java.io,java.utilなどのコアパッケージに関する新機能を紹介していきます。ただし,国際化に関する変更などは別途まとめて紹介する予定です。

Stringクラスの新機能

まずはじめに紹介するのが,Stringクラスです。

Stringクラスの変更はそれほど大きくありません。

オブジェクト生成

バイト列からStringオブジェクトを生成する場合,デフォルトのCharsetを使用するか,文字列でCharsetを指定してきました。

Java SE 6では,Stringオブジェクトの生成にCharsetオブジェクトを直接使用することができるようになりました。

    byte[] b = ...
    String text = new String(b, Charset.forName("UTF-8"));

内部的にはCharsetオブジェクトからCharsetDecoderオブジェクトを生成し,デコードをしています。Charsetを文字列で指定した場合も,内部的にはCharsetクラスを使用しています。

したがって,すでにプログラム中でCharsetクラスを使用している場合,このコンストラクタを使わないとCharsetオブジェクト->文字列->Charsetオブジェクトというように明らかに無駄な文字列を生成しなくてはなりません。

明らかに無駄なオブジェクト生成はなるべく避けたいので,Charsetクラスを直接使用するコンストラクタが定義されたというのはうれしいかぎりです。

文字列が空かどうか調べる

また,ユーティリティメソッドとして,文字列が空かどうかを調べるisEmptyメソッドが新たに定義されています。

文字列が空かどうかというのは,よく判定をするので,このようなユーティリティメソッドは便利です。

    public boolean foo(String message) {
        if (message.isEmpty()) {
// 文字列が空 return false; } else { // 文字列がある ... } }

内部的には,String#length()が0かどうか調べているだけです。

Mathクラス,StrickMathクラス

Mathクラス,StrickMathクラスも新たにメソッドが定義されています。ここではそれらのメソッドを示すだけに留めておきます。

MathクラスとStrickMathクラスで新たに定義されたメソッドはシグネチャは同一ですが,アルゴリズムが違います。Mathクラスは厳密性を犠牲にしてパフォーマンスを向上させ,StrickMathクラスはパフォーマンスは無視して厳密性を重視します。

以下に示すメソッドもNaNの扱いの違いなどのアルゴリズム的な違いがあります。

また,各メソッドは引数がdoubleのものと,floatのものがありますが,以下にはdoubleのものだけを示しておきます。

メソッド 説明
double copySign(double magnitude, double sign) 第2引数の符号を付加した最初の浮動小数点少数を返す
int getExponent(double d) 引数の不変指数を返す
double nextAfter(double start, double direction) 第2引数の方向で,最初に第1引数に隣接する浮動小数点を返す
double nextUp(double d) 正の無限大方向で,引数に隣接する浮動小数点を返す
double scalb(double d, int scaleFactor) d×2scaleFactorを返す

また,これらの新しいメソッドに対応してDoubleクラス,FloatクラスではMIN_NORMALなどの定数が追加されています。

配列のコピー

もう1つ,java.langに関する機能として,配列のコピーがあります。J2SE 5.0までは配列のコピーにはSystem.arraycopyメソッドが使用されてきました。

しかし,System.arraycopyメソッドにはダウンキャストが必須だという問題があります。

せっかく,J2SE 5.0でジェネリクスが導入されたのですから,配列のコピーにもジェネリクスを使用し,ダウンキャストはなるべく排除したいものです。

また歴史的経緯により配列のコピーにSystemクラスが使われていますが,配列に関する機能はjava.util.Arraysクラスにまとめてもらいたいところです。

そこで,新たに定義されたのがArrays.copyOfメソッドです。

copyOfメソッドは今までのarraycopyクラスに比べるとずっと使いやすくなっています。

サンプルのソース ArrayCopySample.java

copyOfメソッドは他のArraysのメソッドと同様にstaticなので,インスタンス化せずに使用することができます。

        String[] dayOfWeek = {"Sun", 
                              "Mon",
                              "Tue",
                              "Wed",
                              "Thu",
                              "Fri",
                              "Sat"};

        String[] dayOfWeek2 = Arrays.copyOf(dayOfWeek,
                                            dayOfWeek.length);
        showArray(dayOfWeek2);
		
        // コピー元の長さより,コピー長が短い場合
        String[] dayOfWeek3 = Arrays.copyOf(dayOfWeek, 4);
        showArray(dayOfWeek3);
 
        // コピー元の長さより,コピー長が長い場合
        String[] dayOfWeek4 = Arrays.copyOf(dayOfWeek, 10);
        showArray(dayOfWeek4);

copyOfメソッドの第1引数はコピー元の配列,第2引数はコピーする長さです。第1引数はジェネリクスでパラメター化されており,戻り値は第1引数と同じ型の配列となります。

なお,showArrayメソッドは配列を標準出力に出力するために作成したメソッドです。

System.arraycopyメソッドを使う場合よりも,キャストがないので,スッキリして見えませんか。

これを実行してみると,次のようになります。

C:\>java ArrayCopySample
Sun Mon Tue Wed Thu Fri Sat
Sun Mon Tue Wed
Sun Mon Tue Wed Thu Fri Sat null null null
 
C:\>

コピー長が元の配列長よりも短い場合でも,指定した長さの配列がでています。逆にコピー長が元の配列長より長い場合は,nullでパディングされることが分かります。

もちろん,ジェネリクスを使用しているので,コピー元とコピー先の型が異なる場合はコンパイルエラーとなります。

Arrays.copyOfメソッドは内部的にSystem.arraycopyメソッドを呼びだしているだけなので,シンタックスシュガーでしかありません。しかし,copyOfメソッドが定義されたことで,キャストが排除でき,型のチェックをコンパイル時に行なうことができます。

java.langパッケージの変更点はこれだけです。意外にあっさりしていると思いませんか。

来週はjava.ioパッケージの新機能を紹介します。

著者紹介 櫻庭祐一

横河電機 ネットワーク開発センタ所属。Java in the Box 主筆

今月の櫻庭

5月の今月の櫻庭でツバメのことを書きました。その後,4羽のヒナが生まれ,成長し,巣立ちしてしまいました。もちろん自分が飼っていたわけではありませんが,巣立ちしてしまった後は一抹の寂しさを感じていました。

ところが,その巣のそばにもう1つツバメの巣があることを最近発見しました。こちらの巣はまだ卵を温めているところです。通勤途中にツバメの様子をうかがうのが,毎日の日課になっています。

生まれてすぐの頃 羽が抜け替わりだす もうすぐ巣立ち
生まれてすぐの頃 羽が抜け替わりだす もうすぐ巣立ち