The King's Museum

ソフトウェアエンジニアのブログ。

【Effective Java】項目43:null ではなく空配列か空コレクションを返す

配列やコレクションを返すメソッドは、null を返すべきではありません。 null の代わりに空の配列か空のコレクションを返すべきです。

null を返すとメソッドを利用するコードには null チェックが必要になるため、コードが煩雑になります。 そこで null チェックを忘れると NullPointerException が発生するかもしれません。

一方、空配列か空コレクションを返しておけば煩雑さも減りますし、NullPointerException の心配もありません。

メソッドが null を返すイディオムは配列と長さを別々に返す C 言語の名残でしょう。 Java でそのイディオムを利用する必要はありません。

パフォーマンス

戻り値を null にすると配列を生成するコストを回避できるので好ましい、と言われることがあります。 この主張は正しくありません。

まず、対象のメソッドがパフォーマンス上の本当の原因であるかを示す必要があります。 多くの場合、空配列の生成がボトルネックになることは多くありませんし、このレベルの最適化が必要になることは通常ありえません。

もしそうせざるを得ない場合は、空配列を一度だけ生成し、それを再利用する方式を利用するべきです。 そうすれば配列を生成するコストは問題になりません。

もし、リストを配列化して返す必要があるならば次のようなイディオムが利用できます。

private final List<Cheese> cheeses = ...;

private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];

public Cheeses[] getCheeses() {
    return cheeses.toArray(EMPTY_CHEESE_ARRAY);
}

toArray メソッドは渡された配列の長さが十分ならば、それに要素をコピーしてその配列を返します。 getCheeses() の処理では、もし cheeses の長さが 1 以上ならば新たな配列が生成されます。 一方、cheeses の長さが 0 ならば EMPTY_CHEESE_ARRAY がそのまま返されるため、空配列の生成コストはかかりません。

一方、リストをコピーして返す必要があるならば以下のように Collections.emptyList() を利用するとよいでしょう。

private final List<Cheese> cheeses = ...;

private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];

public List<Cheese> getCheeses() {
    if (cheeses.isEmpty()) {
        return Collections.emptyList(); // 常に同一の空リストを返す
    } else {
        return new ArrayList<Cheese>(cheeses);
    }
}

Collections には emptylist の他にも emptySet、emptyMap メソッドがあるので Set や Map にも利用できます。

(c) The King's Museum