Androidでlambdaとか

Androidとかいうjavaっぽい何かを触っていますけど、
奴はlambdaとか使えないしlambda禁止令がどうとか以前の問題で辛いですね

ScalaでAndroidを！といってもapkのサイズは肥大化するし、多分仕事でOKでないところのほうが多いと思います

---

そんな昨今、[retrolambda](https://github.com/orfjackal/retrolambda)というかなり素敵なものを教わったのでメモ

なお、Qiitaにすでに[Androidでラムダ式を使いたい](http://qiita.com/kamimoo/items/f4b3ef22ca0327e88e32)というエントリーが5月に上がっています

一刻も早くサンプルコード見たい人は[こちら](https://github.com/daneko/android_retrolambda_functionaljava_sample/blob/master/app/src/main/java/com/example/sample/MyActivity.java#L63)へ

### ハマったその１

OS:Linux Mint 17 と mac OSX 10.9.4 で確認

とりあえず[gradle-retrolambda](https://github.com/evant/gradle-retrolambda)のREADMEに従えば大丈夫ですが…

retrolambdaそのものを最新(1.6.1)指定にするとコンパイルに失敗します

多分この[issue](https://github.com/evant/gradle-retrolambda/issues/45)あたりですかね

```
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileRetrolambdaDebug'.
> Process 'command '/usr/lib/jvm/java-8-oracle/bin/java'' finished with non-zero exit value 1
```

1.6.0指定の時は大丈夫だったので、retrolambdaConfigは指定しない(defaultの1.4.0)かコンパイルできるものを指定しましょう

その他[Known Issues](https://github.com/evant/gradle-retrolambda#known-issues)は見ときましょう

とりあえず retrolambda.incremental は false にしておくのが無難なようですね


### ハマったその２

AndroidStudioでいざBuildしてみたら

```
Execution failed for task ':app:patchAndroidJar'.
> Retrolambda: null/jre/lib/rt.jar does not exist, make sure that the environment variable JAVA_HOME or JAVA8_HOME, or the gradle property retrolambda.jdk points to a valid version of java8.
```
みたいなエラーががが

で、consoleでコンパイルしたら通る！みたいな。

これに関しては[こちらへ](https://github.com/evant/gradle-retrolambda/issues/17#issuecomment-35983623)

### 懸念点

Java6or7とJava8の2つがコンパイル環境として必要になります

gradle-retrolambdaでは
JAVA6_HOME/JAVA7_HOME/JAVA8_HOME みたいな感じでそれぞれexportしていれば楽ですけど、
例えばみんなの開発マシンにそれを強要したり、CI環境もそういう準備をしたり…という部分がちょっとハードル高いかも？

仮想環境構築もchefやansibleでらくらく！という人たちだけならなんの問題も無いでしょう。

### とりあえず動かす

こんなコードが動きます。

そういやScalaでAndroidアプリ書いても、View#senOnClickListener とかには無名クラス突っ込む必要あったな…
java8様様です

```java
view.findViewById(R.id.button1).
    setOnClickListener(v ->
        Toast.makeText(getActivity(), "test", Toast.LENGTH_LONG).show()
    );
```

### だが物足りない

正直これだけでは物足りないと思います。

特にListの処理とか…

結局StreamApiが使えるわけではないのでよくサンプルでありそうなこんなコードを書いてもコンパイルで死にます

```java
List<Integer> list = Arrays.asList(1,2,3,4);
Integer sum = list.stream()
    .map(i -> i * 2)
    .reduce(0,(x,y) -> x + y);
```

```
Error:(64, 31) error: cannot find symbol method stream()
Error:Execution failed for task ':app:compileDebugJava'.
> Compilation failed; see the compiler error output for details.
```

retrolambdaはあくまでもラムダ構文のサポートですので
もちろんそれのあるなしは大きいですけどね

でもきっとあなたのAndroidアプリには[Guava](https://code.google.com/p/guava-libraries/)あたりが入っていると思います

なのでこんな感じで書けるようになりますね

```java
FluentIterable.from(Arrays.asList(1, 2, 3, 4)).
    filter(i -> i % 2 == 0).
    transform(i -> i * 2).
    toList();
```

new Function とか書かなくて良いし、これがAndroidで動くとは！！

すでにGuavaに依存している部分は今すぐ書き直したいですね！

View#setOnClickListenerとかがスッキリ書ける部分よりも、
こっちのほうが嬉しいところも多々ありますね！？

素晴らしい時代だ！！

### だが待ってほしい

reduce/foldが無いなんて…Guavaさん信じてたのに…

ってことがよくありますよね。

このままではIntのListの合計すらままならない…

[LombokのExtensionMethod](http://projectlombok.org/features/experimental/ExtensionMethod.html)で生やすか？

いやしかし…

そうだ[FunctionalJava](https://github.com/functionaljava/functionaljava)だ！

結果がこうなります

```java
final Integer sum = fj.data.List.list(1, 2, 3, 4).
    filter(i -> i % 2 == 0).
    map(i -> i * 2).
    foldLeft(x -> y -> x + y, 0);
```

よく考えたらGuavaのOptionalにbindほしいなぁ…というのもFunctionalJavaを入れるだけで解決！

もう自分で追加しなくていいんだ…ｗ

### final…もめんどい

[Lombokのval](http://projectlombok.org/features/val.html)を使いましょう

以下こうなる

```java
val sum = fj.data.List.list(1, 2, 3, 4).
    filter(i -> i % 2 == 0).
    map(i -> i * 2).
    foldLeft(x -> y -> x + y, 0);
```

Scalaを使わずともここまで出来る時代だったのか！

IDEで赤くなるのは置いといて…ｗ


### 終わりに

個人の趣味で作る分にはなんの問題も無いと思いますが、

* retrolambdaとfunctionaljavaを入れたいんです！

ってのを周りに説得するほうが大変な気がします。

なのでこっそり足すことをオススメします（責任は取りません）

まーでもretrolambdaぐらい入れたいなぁ…

Scalaで書けるなら個人的にそっちのほうが望ましいんですけどね。