第1章 ラムダ式とは : 問題 12 : インターフェースのデフォルトメソッド追加の安全性
問題 12
インターフェースにメソッドを追加することは、デフォルトメソッドであれば問題ない(はず…)
インターフェースへのデフォルトメソッドの追加は、どれぐらい安全か?
Collection
インターフェースの新たなstream
メソッドのせいで、古いコードのコンパイルが失敗するシナリオを述べよ
解答
安全ではない。
具象クラスでstream
メソッドを定義している(アクセス修飾子に係わらず)と、コンパイルエラーになる。
例えば、独自のList<Integer>
の具象クラスFooList
が
public class FooList extends AbstractList<Integer> { private final int size; public FooList(int size) { this.size = size; } public Integer get(int index) { return Integer.valueOf(index); } public int size() { return size; } // ここまでは List の機能を満たすためのコードで問題ない public void stream() { System.out.println("Called FooList#stream()"); } }
となっていた場合、Java 8 ではコンパイルエラーとなる。
さらに問題
バイナリ互換性についてはどうか?
解答
バイナリ互換性は保障される。
即ち、上のFooList
を Java 8 以前でコンパイルして、その Jar ファイルを Java 8 から参照することは可能である。
じゃあFooList
のstream
メソッドを呼ぶと何が起こるでしょう。
List<Integer> list = new FooList(10); ((FooList)list).stream(); // "Called FooList#stream()" System.out.println("FooList の個数 : " + list.stream().count()); // "10個"
FooList
にキャストするとFooList
独自のメソッドが呼ばれ、
List
としてみたときはList
インターフェースのデフォルトメソッドが呼ばれる。
つまり、そのインスタンスの型を具象クラスとするか親のインターフェースにするかで動きが違ってくるということである。
これは、今までの Java にはなかった挙動だ。