tokuhirom's Blog

[java]インターフェースにArrayを露出させた場合の話

Java の世界ではプリミティブな配列が存在している。 プリミティブな配列は速度が List などと比べると圧倒的に速いのでついつい使いたくなる。

しかし、Java 言語では immutable な配列を作ることができないので、内部で配列を保持している場合、それをそのまま返却することはできない。

つまり、以下のようなクラスはよくない。Foo(o).getO() で取得された配列を操作すると、Foo を作成した時点で作成された o を変更してしまうからだ。

public class Foo {
	private final Object[] o;
	public Foo(Object[] o) {
		this.o = o;
	}
	public Object[] getO() {
		return this.o;
	}
}

よって、汎用的なライブラリでは以下のようにしたほうがベター。

public class Foo {
	private final Object[] o;
	public Foo(Object[] o) {
		this.o = o;
	}
	public Object[] getO() {
		return this.o.clone();
	}
}

しかしこれでは、配列のコピーが発生してしまって、データが大きい場合に問題になる。 そこで、配列をあきらめて List を使う。

public class Foo {
	private final List<Object> o;
	public Foo(final List<Object> o) {
		this.o = Collections.unmodifieableList(o);
	}
	public List<Object> getO() {
		return this.o;
	}
}

これで、安全になった。 Collections.unmodifieableList を通していることにより、内部データを操作される心配はもはやない(Reflection とか使われたらアレだけど、それは自己責任)。

まとめ

Java ではオブジェクトの外部とのやりとりに配列を使うのはできるだけ避けたほうがよいケースがある。 (内部ではパフォーマンスを出すために使ったほうがいいケースも多々ある)