Java8が好きになる話（StreamAPIの話はしない） その3 インターフェースのデフォルト実装

今回もラムダ書きますけど、重要なのはそこではないので勘弁してください。

java8でインターフェースでデフォルト実装が書けるようになりました。
参考：http://www.ne.jp/asahi/hishidama/home/tech/java/interface.html#h_default_method
いつ使うの？abstractクラスの実装と何が違うの？と言われると「うっ」ってなりますが、
個人的な意見では仕様変更（機能追加）に強くなったのかと思ってます。
（[関数型インターフェース](http://www.ne.jp/asahi/hishidama/home/tech/java/functionalinterface.html)では多用しますけど今回はその話はしません。）

#例（仕様）
Containerインターフェースはkeyとuserから情報を返します。
実装クラスに下記の2種類[^3]があります。

* 生成時に情報をロードしてキャッシュします。要求にはキャッシュから情報を返します。
* 要求に対して情報をロードして返します。一度ロードした情報はキャッシュします。

#コード
```java
	/**
	 * インターフェース
	 */
	public interface Container {
		/**
		 * keyとuserから情報を返す
		 */
		String get(String key, String user);
	}

	public static class CacheContainer implements Container {
		private final Map<String, Map<String, String>> map = new HashMap<>();

		public CacheContainer() {
			//TODO 初期処理でmapに情報を積む
		}

		@Override
		public String get(String key, String user) {
			return this.map.getOrDefault(key, Collections.emptyMap()).get(user);
		}
	}

	public static class DemandContainer implements Container {
		private final Map<String, Map<String, String>> map = new HashMap<>();

		@Override
		public String get(String key, String user) {
			return this.map.computeIfAbsent(key, k -> new HashMap<>())
					.computeIfAbsent(user, k -> this.getFromDB(key, user));
		}

		/**
		 * たとえばDBから値をとってきて返す。
		 */
		private String getFromDB(String key, String user) {
			return null;//TODO DBからとってくる処理
		}
	}
```

#機能拡張（default実装なし[^1]）
これに機能拡張が必要になって、
Containerに

```java
String get(String key);
```
というメソッドを増やして、get(key,"DEFAULT");と同じ動きをさせたい。
みたいな要件来たらどうします？

```java:default実装なし
	/**
	 * インターフェース
	 */
	public interface Container {
		/**
		 * keyとuserから情報を返す
		 */
		String get(String key, String user);

		/**
		 * keyから情報を返す<br>
		 * get(key,"DEFAULT");と同様
		 */
		String get(String key);
	}

	public static class CacheContainer implements Container {
		private final Map<String, Map<String, String>> map = new HashMap<>();

		public CacheContainer() {
			//TODO 初期処理でmapに情報を積む
		}

		@Override
		public String get(String key, String user) {
			return this.map.getOrDefault(key, Collections.emptyMap()).get(user);
		}

		//New!!
		@Override
		public String get(String key) {
			return this.get(key, "DEFAULT");
		}
	}

	public static class DemandContainer implements Container {
		private final Map<String, Map<String, String>> map = new HashMap<>();

		@Override
		public String get(String key, String user) {
			return this.map.computeIfAbsent(key, k -> new HashMap<>())
					.computeIfAbsent(user, k -> this.getFromDB(key, user));
		}

		//New!!
		@Override
		public String get(String key) {
			return this.get(key, "DEFAULT");
		}

		/**
		 * たとえばDBから値をとってきて返す。
		 */
		private String getFromDB(String key, String user) {
			return null;//TODO DBからとってくる処理
		}
	}
```
あーあ。2か所に同じこと書くなんて。
abstractクラスかませておけばよかったと後悔するしかないですね。
実装クラスが2つしか無かったことが不幸中の幸いです。

#機能拡張（java8 default実装）
java8のdefault実装ならば！！！

```java:java8
	/**
	 * インターフェース
	 */
	public interface Container {
		/**
		 * keyとuserから情報を返す
		 */
		String get(String key, String user);

		/**
		 * keyから情報を返す<br>
		 * get(key,"DEFAULT");と同様
		 */
		default String get(String key) {
			return this.get(key, "DEFAULT");
		}
	}
```
とdefaultメソッド増やすだけでOK！

#おまけ
こういう感じでメソッドを増やすことができるdefaultメソッドのおかげで
java8のCollectionやMapたちも大成長を遂げたといっても過言ではありませんね。
参考：http://www.lambdafaq.org/what-are-default-methods/
（英語。僕はGoogle翻訳で読みました）
そういう意味でもデフォルト実装は大好きです。

#おまけ2
Iteratorを実装することってあります？
僕はほんとたまにあるんですけど[^2]、removeをサポートしないことがほとんどで、

```java
    public void remove() {
        throw new UnsupportedOperationException("remove");
    }
```
って毎度書くのだるいなー。っと思ってたら、
これデフォルト実装されているので書く必要なくなりましたよ！！

[その4](http://qiita.com/ota-meshi/items/86e22b790d54819e2012)につづく。

その1：[Java8が好きになる話（StreamAPIの話はしない） その1 Map#computeIfAbsentとList#sort](http://qiita.com/ota-meshi/items/31f36d38d4da8fce3c57)
その2：[Java8が好きになる話（StreamAPIの話はしない） その2 Optional#map](http://qiita.com/ota-meshi/items/dbdd592b613e38b7a4bb)

[^1]: 「java7以前」って書きたかったんですけど「default実装なし」と書いたのは、すでにラムダやら使っちゃってるからです。
[^2]: 年月の無限イテレータとか作りました。昔。
[^3]: 本番機用とデバッグ用でこんな感じに分けたりしません？