JJUG CCC 2015に出て、Valhallaとかの名前も聞きつつ、でも Androidじゃ使えないんだろうなあと暗い気持ちになりながら、そもそも Androidは Java7対応してる、といえるのが気になっていた。のでちまちま書いていたのがこちらです。でも書き飛ばしてしまった気もするのでツッコミとか歓迎です。
そもそも JDK7での拡張機能というのはいろいろある。Oracleによるリリースノート から、関係しそうな機能だけを抜粋してみると以下の様なものがある:
- IO and New IO
- Security
- Concurrency Utilities
- Internationalization
- java.lang Package
- Multithreaded Custom Class Loaders in Java SE 7
- Java Programming Language
- Binary Literals
- Strings in switch Statements
- The try-with-resources Statement
- Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking
- Underscores in Numeric Literals
- Type Inference for Generic Instance Creation (ダイアモンド演算子)
- Java Virtual Machine (JVM)
- Java Virtual Machine Support for Non-Java Languages
- Garbage-First Collector
- Java HotSpot Virtual Machine Performance Enhancements
これらの機能はさまざまなレイヤーで実現されており、そのレイヤーを知ることが Androidでの対応可能性を大まかに知るのに有効だ。
javac
一番上流のレイヤーであり、build環境でどうにでもできる。ここだけで対応できる新機能なら、Androidでも使えるはずだ。さらにいえば、JDK8の javacで Androidのコードのコンパイルもできる。JDK7互換の classファイルをはいてもらうよう設定しなければならないが。
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
ここで対応してるもの、すなわち Androidでも使えるのは以下の通り:
- binary literal
- String switch statement
- Catching multiple exception type
- Underscores in Numeric Literals
- Type inference for Generic Instance Creation (ダイアモンド演算子)
java library
JDKでは jarで配布されていて、complie時に参照され、実行時に linkされる。つまり、実機上に対応する class がないと動かないことになる。で、このライブラリは基本的に Android 本体と一緒になっているので、実機の sdkVersionによって使えるかどうか決まる。
端的に言えば、 minSdkVersionで使えるなら使ってもいいだろう。
どの sdkLevelでどの APIが使えるかは、各 sdkLevelの android.jarをのぞけばいいだろう。もっと頑張ると、reflectionを使って android.jarにはないけど実機にはある APIとかを呼ぶこともできるらしいけど、そんなので対応しているというのもおかしいし。
ということで script書いて、各バージョンの android.jar の java.*
pakcageにあるクラスを吐き出させてみた。wcした結果がこちら:
1014 1014 31556 sdk-android-10
1014 1014 31556 sdk-android-15
1014 1014 31556 sdk-android-16
1014 1014 31556 sdk-android-17
1021 1021 31761 sdk-android-19
1021 1021 31761 sdk-android-20
1035 1035 32300 sdk-android-21
1035 1035 32300 sdk-android-22
1035 1035 32300 sdk-android-23
ご覧のように 2段階のジャンブがある。
19になって新しく入ったのは以下のとおり:
- java.lang.AutoCloseable
- java.lang.ReflectiveOperationException
- java.lang.SafeVarargs
- java.nio.charset.StandardCharsets
- java.util.Objects
AutoCloseableとかが入ったので try-with-resourcesが使えるようになったってことですね。
21になって入ったのは以下のとおり:
- java.util.IllformedLocaleException
- java.util.Locale$Builder
- java.util.concurrent.ConcurrentLinkedDeque
- java.util.concurrent.ForkJoinPool
- java.util.concurrent.ForkJoinPool$ForkJoinWorkerThreadFactory
- java.util.concurrent.ForkJoinPool$ManagedBlocker
- java.util.concurrent.ForkJoinTask
- java.util.concurrent.ForkJoinWorkerThread
- java.util.concurrent.LinkedTransferQueue
- java.util.concurrent.Phaser
- java.util.concurrent.RecursiveAction
- java.util.concurrent.RecursiveTask
- java.util.concurrent.ThreadLocalRandom
- java.util.concurrent.TransferQueue
concurrent系が入ってますね。そこら辺を駆使するコードは書いたことないのでどの程度の有り難みがあるのかわからないけど。
で、java.nio.file
あたりは sdk23になっても入ってません。無念。
本当は Java 1.7の jarと比較してみようとも思ったんですが、あまりにも違いすぎてまとめるのができませんでいした。さらに、上記の sdkVersionごとの比較も classの有無の比較だけなので、そのなかで methodが追加されてたりしててもわかりませんのでそこらへんはご容赦ください。
JVM
本来の Javaなら JVMレベルで実現される機能である。とはいえ、ご存知のように Androidは JVMを使っていない。まず、dexに変換され、5.xより前では Dalvik VMで、それ以降では ARTで実行されることになる。
この部分の改善が Androidに適用できることは少ない。そもそも前提とする仕組みが違うし。
その中で、invokedynamicは頑張れば適用できそうな例なのに適用できていない。まあ、JDK8のいろいろな機能も同時に移植しないと意味がないからやってないのか、Oracleが怖いのか。invokedynamicだけがあれば lambda周りのすべての機能が使えるわけでもないしねえ。
- Java Virtual Machine Support for Non-Java Languages (invokedynamic)
- Garbage-First Collector
- Java Hotspot Virtual Machine Performance Enhancements
まとめ
ライブラリのあたりの業の深さが目立つ。まあ、そのまま移植しても仕方ない APIとかもあるからしょうがないけどあって良さそうなものもない。
ほかの視点から見た互換性の考え方もあるかもしれない。というかあるじゃないなかなあ。識者の方はぜひ教えてほしいです。