188

Just wondering if anyone has tried using new Java 7 language features with Android? I know that Android reads the bytecode that Java spits out and turns it to dex. So I guess my question is can it understand the bytecode of Java 7?

Daniel Ryan
  • 6,976
  • 5
  • 45
  • 62
  • 10
    Alternatively, maybe you can use the Java 7 language features but compile to Java 6 bytecode? – Tyler Aug 22 '11 at 21:49
  • 2
    Android Studio will now give you a notification when creating a new project: "With minSdkVersion less than 19, you cannot use try-with-resources, but other Java 7 language features are fine" – IgorGanapolsky Dec 30 '13 at 18:50
  • 1
    Yeah I know :) We are finally using Java 7 in our project. – Daniel Ryan Jan 05 '14 at 22:04

8 Answers8

165

If you are using Android Studio, the Java 7 language should be enabled automatically without any patches. Try-with-resource requires API Level 19+, and NIO 2.0 stuff are missing.

If you can't use Java 7 features, see @Nuno's answer on how to edit your build.gradle.

The following is for historical interest only.


A small part of Java 7 can certainly be used with Android (note: I have only tested on 4.1).

First of all, you could not use Eclipse's ADT because it is hard-coded that only Java compiler 1.5 and 1.6 are compliant. You could recompile ADT but I find there is no simple way to do that aside from recompiling the whole Android together.

But you don't need to use Eclipse. For instance, Android Studio 0.3.2, IntelliJ IDEA CE and other javac-based IDEs supports compiling to Android and you could set the compliance even up to Java 8 with:

  • File → Project Structure → Modules → (pick the module at the 2nd pane) → Language level → (choose "7.0 - Diamonds, ARM, multi-catch, etc.")

Enabling Java 7 on IntelliJ

This only allows Java 7 language features, and you can hardly benefit from anything since a half of improvement also comes from the library. Features you could use are those which do not depend on the library:

  • Diamond operator (<>)
  • String switch
  • Multiple-catch (catch (Exc1 | Exc2 e))
  • Underscore in number literals (1_234_567)
  • Binary literals (0b1110111)

And these features cannot be used yet:

  • The try-with-resources statement — because it requires the non-existing interface "java.lang.AutoCloseable" (this can be used publicly in 4.4+)
  • The @SafeVarargs annotation — because "java.lang.SafeVarargs" does not exist

... "yet" :) It turns out that, although Android's library is targeting for 1.6, the Android source does contain interfaces like AutoCloseable and traditional interfaces like Closeable does inherit from AutoCloseable (SafeVarargs is really missing, though). We could confirm its existence via reflection. They are hidden simply because the Javadoc has the @hide tag, which caused the "android.jar" not to include them.

There is already as existing question How do I build the Android SDK with hidden and internal APIs available? on how to get those methods back. You just need to replace the existing "android.jar" reference of the current Platform with our customized one, then many of the Java 7 APIs will become available (the procedure is similar to that in Eclipse. Check Project Structure → SDKs.)

In additional to AutoCloseable, (only) the following Java 7 library features are also revealed:

  • Exception chaining constructors in ConcurrentModificationException, LinkageError and AssertionError
  • The static .compare() methods for primitives: Boolean.compare(), Byte.compare(), Short.compare(), Character.compare(), Integer.compare(), Long.compare().
  • Currency: .getAvailableCurrencies(), .getDisplayName() (but without .getNumericCode())
  • BitSet: .previousSetBit(), .previousClearBit(), .valueOf(), .toLongArray(), .toByteArray()
  • Collections: .emptyEnumeration(), .emptyIterator(), .emptyListIterator()
  • AutoCloseable
  • Throwable: .addSuppressed(), .getSuppressed(), and the 4-argument constructor
  • Character: .compare(), .isSurrogate(), .getName(), .highSurrogate(), .lowSurrogate(), .isBmpCodePoint() (but without .isAlphabetic() and .isIdeographic())
  • System: .lineSeparator() (undocumented?)
  • java.lang.reflect.Modifier: .classModifiers(), .constructorModifiers(), .fieldModifiers(), .interfaceModifiers(), .methodModifiers()
  • NetworkInterface: .getIndex(), .getByIndex()
  • InetSocketAddress: .getHostString()
  • InetAddress: .getLoopbackAddress()
  • Logger: .getGlobal()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer: .hasQueuedPredecessors()
  • DeflaterOutputStream: the 3 constructors with "syncFlush".
  • Deflater: .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate() with 4 arguments

That's basically all. In particular, NIO 2.0 does not exist, and Arrays.asList is still not @SafeVarargs.

Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • Very interesting research! Hope this will lead into official Java 7 support on Android in some reasonably short time. – Natix Dec 10 '12 at 19:28
  • are you saying it is possible to develop in JDK 7 & Android using the inteliJ IDE ? – android developer Dec 13 '12 at 06:53
  • 2
    Great answer. I hope full jvm level support will happen soon in future, `nio2` and other goodies will definitely be a good news. – S.D. Feb 02 '13 at 07:53
  • 4
    Worth to mention that `AutoCloseable` interface doesn't exist in Android runtime until ICS (or perhaps until HoneyComb). So even if you use patched android.jar you'll receive `NoClassDefFoundError` on 2.x system. – Volo Mar 16 '13 at 10:52
  • I posted an answer below of a git project that does allow you to use some Java 7 features, which solve some issues listed in this post. – Daniel Ryan May 13 '13 at 05:03
  • This trick works only for Java7. Any advices how we can use Java8 lambdas? – deviant Oct 19 '13 at 10:37
  • 2
    @deviant: That requires modifying the Dalvik VM, since Java 8 lambda uses `invokedynamic` which is not supported by the JVM targeting Java 6. – kennytm Oct 20 '13 at 06:20
  • 2
    You might want to add an update that as of Android studio 3.2, Language level 7 is fully supported, as is try-with-resources if you're compiling against KitKat – JRaymond Nov 01 '13 at 00:21
  • 4
    try with resources can now be used on SDK 19 (Android Kitkat). see http://tools.android.com/recent/androidstudio032released – Mohamed El-Nakeep Nov 01 '13 at 01:50
  • 1
    what about ADT ? is there the possibility to use java 7 with adt? – Blackbelt Nov 20 '13 at 08:16
  • 1
    @blackbelt yes, read my answer on http://stackoverflow.com/questions/20480090/does-android-support-jdk-6-or-7/ – Mohamed El-Nakeep Apr 15 '14 at 04:56
  • 1
    @blackbelt starting with ADT 22.6 – Mohamed El-Nakeep Apr 15 '14 at 04:58
  • In Android Studio 1.0.2 the option is called `Source Compatibility` instead of `Language Level` – user905686 Jan 02 '15 at 11:35
  • Quick question, does Android support `Files.move()` method ? Beginning from what version ? – Jonas Czech May 03 '15 at 12:57
  • @JonasCz No, the class does not exist in the Android runtime. – kennytm May 03 '15 at 14:24
  • try-with-resources statement can be used, it's a syntax sugar, there are no runtime dependent on java.lang.AutoCloseable – zufuliu Nov 09 '15 at 13:54
70

EDIT: At the time this was written, the latest release was Android 9 and Eclipse Indigo. Thing have changed since then.

  • Practical answer

Yes, I have tried. But this is not a great test as the compatibility was limited to level 6 with no way (no simple way at least) to really use java 7:

  • First I installed a JDK7 on a machine that had no other JDK installed - Eclipse and Android are not installed either:

The 7 is the only installed on this machine

  • Then I installed a brand new Eclipse Indigo and checked it was actually using the JDK 7 (well, as this is the only one and as this is the one I've selected I would have been surprised)

The 7 is the only used by this Eclipse

  • Then I installed the latest version of the Android SDK (EDIT: Honeycomb, API13, at the time this post was written). It found my JDK 7 and installed properly. The same for ADT.

  • But I had a surprise when trying to compile and run a Hello Word Android app. The compatibility was set to Java 6 with no way to force it to Java 7:

Compatibility is limited to Java 6

  • I tried with a non-Android project, a regular Java one, and I had the explanation. The compatibility level seems to be limited by Eclipse (see the message at bottom of the following image):

Eclipse limits itself to level 6 compatibility

So I had Hello World working, and also other apps, more complicated and using SQLite, Listview, Sensor and Camera, but this only proves that the compatibility handling of Java 7 seems to be well done and working with Android.

So, did someone try with the good old Ant, to bypass the Eclipse limitation seen above?

  • Theroetical answer

Anyway, the SDK is designed to be used with Java 5 or 6, as explained here.

We may have something working with Java 7, but it would be working "by accident". The building of the DEX may work properly or not, and once the DEX built, it may work or not. This because using a non-qualified JDK gives unpredictable results by definition.

Even if someone has succesfully built an Android app under plain Java 7, this does not qualify the JDK. The same process applied to another application may fail, or the resulting application may have bugs tied to the use of that JDK. Not recommended.

For those who are involved on webapps development, this exactly the same as deploying a web application built under Java 5 or 6 under an application server qualified for Java 4 only (let's say Weblogic 8 for example). This may work, but this is not something that can be recommended for other purposes than trying.

Shlublu
  • 10,917
  • 4
  • 51
  • 70
  • 1
    Thanks for that detailed review. So looks like you can't use Java 7 language features but still use Java 7 as Java 6. Hopefully this changes soon :) – Daniel Ryan Aug 25 '11 at 02:15
  • This is with Eclipse. With Ant, this is probably possible. I hope someone will do the test and I blame myself for being too lazy to do it :) – Shlublu Aug 25 '11 at 06:26
  • Yes Varga, but I don't think the compiler version limitation comes from Ant but from Eclipse. – Shlublu Nov 13 '11 at 09:39
  • 2
    Also do note that if your toying with multiple versions of Java the tools provided are not compatible. What I mean is that if you first signed your app with jarsigner from java 6 tools and then later installed java 7 and signed a new version of our app with the jarsigner that came with java 7 and the same keystore as previously the signatures would not match! – Timo Oct 24 '12 at 11:14
38

Quote from dalvikvm.com:

dx, included in the Android SDK, transforms the Java Class files of Java classes compiled by a regular Java compiler into another class file format (the .dex format)

That means, the .java source file does not matter, it's only the .class bytecode.

As far as I know, only invokedynamic was added to the JVM bytecode in Java 7, the rest is compatible to Java 6. The Java language itself does not use invokedynamic. Other new features, like the switch statement using Strings or the multi-catch are just syntatic sugar and did not require byte code changes. For example, the multi-catch just copies the catch-block for each possible exception.

The only problem should be that the new classes introduced in Java 7 are missing in Android, like AutoCloseable, so I'm not sure if you can use the try-with-resources feature (somebody tried it?).

Any comments on that? Am I missing something?

Andi
  • 3,234
  • 4
  • 32
  • 37
  • 2
    Now the problem is how do we configure such that Java 7 source codes compile to Java 6 class files, especially in eclipse? – Randy Sugianto 'Yuku' Nov 17 '11 at 13:26
  • The only question remaining is why would you even bother? – Warpzit Dec 16 '11 at 14:08
  • @Warpzit the bigger question should be **Why a developer won't bother for all this confusion ?** – Amit Oct 30 '12 at 08:22
  • @Amit because he's come to realize Android is different from Java and in order to work with Android he has to use the tools that is offered. – Warpzit Oct 30 '12 at 09:01
  • 2
    @Warpzit His only question is " **Can Android understand java 7 ?** " Ignorance is never a solution/answer... – Amit Oct 30 '12 at 09:09
12

As of the Android SDK v15, along with Eclipse 3.7.1, Java 7 is not supported for Android development. Setting the source compatibility to 1.7 mandates setting the generated .class file compatibility to 1.7, which leads to the following error by the Android compiler:

Android requires compiler compliance level 5.0 or 6.0. Found '1.7' instead. Please use Android Tools > Fix Project Properties.

Hosam Aly
  • 41,555
  • 36
  • 141
  • 182
5

To expand on the above answer by @KennyTM, if you are targeting 4.0.3 and above (minSdkVersion=15), you can use the hidden APIs by adding a few classes to your target's SDK android.jar.

Once you do this, you can use try-with-resources on any Closeable, as well as implement AutoCloseable in your own classes.

I've made a zip containing sources and binaries of all the classes that needed to be modified in android.jar to make these APIs available. You just need to unpack it and add the binaries to your
android-sdk/platforms/android-NN/android.jar

You can download it from here: http://db.tt/kLxAYWbr

Also of note is that, in the past couple of months, Elliott Hughes has made a few commits to the Android tree: finished off AutoCloseable, added SafeVarargs, unhidden various APIs, fixed Throwable's protected constructor and added support for version 51 class files in dx. So, there is finally some progress going on.

Edit (April 2014):

With the release of SDK 19 it is no longer necessary to patch android.jar with the additional APIs.

The best method to use try-with-resources in Android Studio for an app that targets 4.0.3 and above (minSdkVersion=15) is add the following compileOptions to your build.gradle:

android {
    compileSdkVersion 19
    buildToolsVersion '19.0.3'

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 19
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
}

Android Studio will complain that try-with-resources can't be used with this API level, but my experience is that it can. The project will build and run without issue on devices with 4.0.3 and above. I've experienced no issues with this, with an app that has been installed into 500k+ devices.

Android Studio error

To ignore this warning, add the following to your lint.xml:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>
Nuno Cruces
  • 1,584
  • 15
  • 18
  • 1
    I find it interesting that Android Studio code warning says try-with-resources is new in API 13 and I should be using it. Though don't have time to actually test if it is working correctly. – Daniel Ryan Aug 28 '14 at 02:54
1

It seems that getting this to work with pure ant is a bit of a kludge.

But it worked for me: http://www.informit.com/articles/article.aspx?p=1966024

mako
  • 1,201
  • 14
  • 30
  • 1
    I looked for this for a long time. To cut people trouble through filtering through the article, you'll need to change the ` ` line in the build.xml that's provided by android (not the one in your project!). For me it was in /opt/android-sdk-update-manager/tools/ant/build.xml – Mateusz Kowalczyk Mar 22 '14 at 01:59
  • No you don't. You can overwrite those properties with `custom_rules.xml`, see my answer here: http://stackoverflow.com/a/24608415/194894 – Flow Sep 23 '14 at 17:03
1

In order to use Java 7 features in code build by Android's ant based build system, simply put the following in your custom_rules.xml in your projects root directory:

custom_rules.xml:

<project name="custom_android_rules">
    <property name="java.target" value="1.7" />
    <property name="java.source" value="1.7" />
</project>
1800 INFORMATION
  • 131,367
  • 29
  • 160
  • 239
Flow
  • 23,572
  • 15
  • 99
  • 156
0

Some people might be interested in this git project I've found, that seems to allow to run Java 7 on android. https://github.com/yareally/Java7-on-Android

However too much of a risk if I add this in the current project I work on. So I'll wait until Google to officially support Java 7.

Daniel Ryan
  • 6,976
  • 5
  • 45
  • 62