Fonctionnalités du langage Java 7 avec Android

188

Vous vous demandez simplement si quelqu'un a essayé d'utiliser les nouvelles fonctionnalités du langage Java 7 avec Android? Je sais qu'Android lit le bytecode que Java crache et le transforme en dex. Donc, je suppose que ma question est: peut-il comprendre le bytecode de Java 7?

Daniel Ryan
la source
10
Alternativement, vous pouvez peut-être utiliser les fonctionnalités du langage Java 7 mais compiler en bytecode Java 6?
MatrixFrog
2
Android Studio va maintenant vous donner une notification lors de la création d'un nouveau projet: "Avec minSdkVersion inférieure à 19, vous ne pouvez pas utiliser try-with-resources, mais les autres fonctionnalités du langage Java 7 conviennent"
IgorGanapolsky
1
Ouais je sais :) Nous utilisons enfin Java 7 dans notre projet.
Daniel Ryan

Réponses:

165

Si vous utilisez Android studio , Java 7 langue doit être activée automatiquement sans taches. Try-with-resource nécessite le niveau d'API 19+, et des éléments NIO 2.0 sont manquants.

Si vous ne pouvez pas utiliser les fonctionnalités de Java 7, consultez la réponse de @Nuno sur la façon de modifier votre fichierbuild.gradle .

Ce qui suit est pour l'intérêt historique seulement.


Une petite partie de Java 7 peut certainement être utilisée avec Android (note: je n'ai testé que sur 4.1).

Tout d'abord, vous ne pouvez pas utiliser ADT d'Eclipse car il est codé en dur que seuls les compilateurs Java 1.5 et 1.6 sont compatibles. Vous pouvez recompiler ADT mais je trouve qu'il n'y a pas de moyen simple de le faire en dehors de recompiler l'ensemble d'Android ensemble.

Mais vous n'avez pas besoin d'utiliser Eclipse. Par exemple, Android Studio 0.3.2 , IntelliJ IDEA CE et d'autres IDE basés sur javac prennent en charge la compilation vers Android et vous pouvez définir la conformité même jusqu'à Java 8 avec:

  • Fichier → Structure du projet → Modules → (choisissez le module dans le 2ème volet) → Niveau de langue → (choisissez "7.0 - Diamants, ARM, multi-catch, etc.")

Activation de Java 7 sur IntelliJ

Cela n'autorise que les fonctionnalités du langage Java 7 , et vous ne pouvez guère bénéficier de quoi que ce soit puisque la moitié de l'amélioration provient également de la bibliothèque. Les fonctionnalités que vous pouvez utiliser sont celles qui ne dépendent pas de la bibliothèque:

  • Opérateur diamant ( <>)
  • Commutateur de chaîne
  • Prise multiple ( catch (Exc1 | Exc2 e))
  • Souligner dans les littéraux numériques ( 1_234_567)
  • Littéraux binaires ( 0b1110111)

Et ces caractéristiques ne peuvent pas être utilisés encore :

  • L' tryinstruction -with-resources - car elle nécessite l'interface non existante "java.lang.AutoCloseable" (cela peut être utilisé publiquement dans 4.4+)
  • L'annotation @SafeVarargs - car "java.lang.SafeVarargs" n'existe pas

... "encore" :) Il s'avère que, bien que la bibliothèque d'Android cible pour 1.6, la source Android contient des interfaces comme AutoCloseable et des interfaces traditionnelles comme Closeable hérite d'AutoCloseable (SafeVarargs est vraiment absent, cependant). Nous pourrions confirmer son existence par la réflexion. Ils sont cachés simplement parce que le Javadoc a la @hidebalise, ce qui a empêché "android.jar" de les inclure.

Il y a déjà une question existante Comment créer le SDK Android avec des API cachées et internes disponibles? sur la façon de récupérer ces méthodes. Il vous suffit de remplacer la référence "android.jar" existante de la plate-forme actuelle par notre référence personnalisée, puis de nombreuses API Java 7 deviendront disponibles (la procédure est similaire à celle d'Eclipse. Vérifiez la structure du projet → SDK.)

En plus d'AutoCloseable, (uniquement) les fonctionnalités suivantes de la bibliothèque Java 7 sont également révélées:

  • Constructeurs de chaînage d'exceptions dans ConcurrentModificationException, LinkageError et AssertionError
  • Les méthodes statiques .compare () pour les primitives: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Long.compare ().
  • Devise : .getAvailableCurrency (), .getDisplayName () (mais sans .getNumericCode ())
  • BitSet : .previousSetBit (), .previousClearBit (), .valueOf (), .toLongArray (), .toByteArray ()
  • Collections : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • Fermeture automatique
  • Throwable : .addSuppressed (), .getSuppressed () et le constructeur à 4 arguments
  • Caractère : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (mais sans .isAlphabetic () et .isIdeographic ())
  • Système: .lineSeparator () (non documenté?)
  • java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • NetworkInterface : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • Enregistreur : .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer : .hasQueuedPredecessors ()
  • DeflaterOutputStream : les 3 constructeurs avec "syncFlush".
  • Deflater : .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate () avec 4 arguments

C'est pratiquement tout. En particulier, NIO 2.0 n'existe pas et Arrays.asList n'est toujours pas @SafeVarargs.

KennyTM
la source
2
Très bonne réponse. J'espère que le support complet de niveau jvm arrivera bientôt à l'avenir, nio2et que d'autres goodies seront certainement une bonne nouvelle.
SD
4
Il convient de mentionner que l' AutoCloseableinterface n'existe pas dans l'environnement d'exécution Android avant ICS (ou peut-être jusqu'à HoneyComb). Ainsi, même si vous utilisez android.jar patché, vous recevrez NoClassDefFoundErrorsur le système 2.x.
Idolon
2
@deviant: Cela nécessite de modifier la VM Dalvik, car Java 8 utilise lambda invokedynamicqui n'est pas pris en charge par la JVM ciblant Java 6.
kennytm
2
Vous voudrez peut-être ajouter une mise à jour qui, à partir d'Android Studio 3.2, le niveau de langue 7 est entièrement pris en charge, tout comme try-with-resources si vous compilez avec KitKat
JRaymond
4
try with resources peut désormais être utilisé sur le SDK 19 (Android Kitkat). voir tools.android.com/recent/androidstudio032released
Mohamed El-Nakib
70

EDIT: Au moment où cela a été écrit, la dernière version était Android 9 et Eclipse Indigo. Les choses ont changé depuis.

  • Réponse pratique

Oui, j'ai essayé. Mais ce n'est pas un excellent test car la compatibilité était limitée au niveau 6 sans aucun moyen (pas de moyen simple du moins) d'utiliser vraiment java 7:

  • J'ai d'abord installé un JDK7 sur une machine sur laquelle aucun autre JDK n'était installé - Eclipse et Android ne sont pas installés non plus:

Le 7 est le seul installé sur cette machine

  • Ensuite, j'ai installé un tout nouvel Eclipse Indigo et vérifié qu'il utilisait réellement le JDK 7 (enfin, comme c'est le seul et comme c'est celui que j'ai sélectionné, j'aurais été surpris)

Le 7 est le seul utilisé par cette Eclipse

  • Ensuite, j'ai installé la dernière version du SDK Android (EDIT: Honeycomb, API13, au moment de la rédaction de cet article). Il a trouvé mon JDK 7 et installé correctement. Idem pour ADT.

  • Mais j'ai eu une surprise en essayant de compiler et d'exécuter une application Android Hello Word. La compatibilité a été définie sur Java 6 sans aucun moyen de le forcer à Java 7:

La compatibilité est limitée à Java 6

  • J'ai essayé avec un projet non Android, un projet Java classique, et j'avais l'explication. Le niveau de compatibilité semble être limité par Eclipse (voir le message en bas de l'image suivante):

Eclipse se limite à la compatibilité de niveau 6

Donc j'avais Bonjour tout le monde de travail, et également d' autres applications, plus complexes et l' utilisation SQLite, Listview, Sensoret Camera, mais cela ne prouve que la compatibilité de manipulation de Java 7 semble être bien fait et de travailler avec Android.

Alors, est-ce que quelqu'un a essayé avec la bonne vieille Ant, de contourner la limitation Eclipse vue ci-dessus?

  • Réponse théroétique

Quoi qu'il en soit, le SDK est conçu pour être utilisé avec Java 5 ou 6, comme expliqué ici .

Nous avons peut-être quelque chose qui fonctionne avec Java 7, mais cela fonctionnerait "par accident". La construction du DEX peut fonctionner correctement ou non, et une fois le DEX construit, cela peut fonctionner ou non. En effet, l'utilisation d'un JDK non qualifié donne des résultats imprévisibles par définition.

Même si quelqu'un a réussi à créer une application Android sous Java 7, cela ne qualifie pas le JDK. Le même processus appliqué à une autre application peut échouer ou l'application qui en résulte peut avoir des bogues liés à l'utilisation de ce JDK. Non recommandé.

Pour ceux qui sont impliqués dans le développement d'applications Web, cela revient exactement à déployer une application Web construite sous Java 5 ou 6 sous un serveur d'application qualifié pour Java 4 uniquement (disons Weblogic 8 par exemple). Cela peut fonctionner, mais ce n'est pas quelque chose qui peut être recommandé à d'autres fins que d'essayer.

Shlublu
la source
1
Merci pour cet examen détaillé. Il semble donc que vous ne pouvez pas utiliser les fonctionnalités du langage Java 7, mais que vous utilisez toujours Java 7 comme Java 6. J'espère que cela changera bientôt :)
Daniel Ryan
C'est avec Eclipse. Avec Ant, c'est probablement possible. J'espère que quelqu'un fera le test et je me blâme d'être trop paresseux pour le faire :)
Shlublu
Oui Varga, mais je ne pense pas que la limitation de la version du compilateur vient d'Ant mais d'Eclipse.
Shlublu
2
Notez également que si vous utilisez plusieurs versions de Java, les outils fournis ne sont pas compatibles. Ce que je veux dire, c'est que si vous avez d'abord signé votre application avec jarsigner à partir des outils java 6, puis installé java 7 et signé une nouvelle version de notre application avec le jarsigner fourni avec java 7 et le même keystore que précédemment, les signatures ne correspondraient pas !
Timo
38

Citation de dalvikvm.com:

dx, inclus dans le SDK Android, transforme les fichiers de classe Java des classes Java compilés par un compilateur Java standard en un autre format de fichier de classe (le format .dex)

Cela signifie que le fichier source .java n'a pas d'importance, il ne s'agit que du bytecode .class.

Autant que je sache, seul invokedynamic a été ajouté au bytecode JVM dans Java 7, le reste est compatible avec Java 6. Le langage Java lui-même n'utilise pas invokedynamic . D'autres nouvelles fonctionnalités, comme l' instruction switch utilisant String s ou le multi- catch ne sont que du sucre syntatique et ne nécessitent pas de changements de code d'octet. Par exemple, le multi- catch copie simplement le catch -block pour chaque exception possible.

Le seul problème devrait être que les nouvelles classes introduites dans Java 7 manquent dans Android, comme AutoCloseable , donc je ne suis pas sûr que vous puissiez utiliser la fonction try -with-resources (quelqu'un l'a essayé?).

Des commentaires à ce sujet? Est-ce que je manque quelque chose?

Et moi
la source
2
Maintenant, le problème est de savoir comment configurer de telle sorte que les codes source de Java 7 se compilent en fichiers de classe Java 6, en particulier dans eclipse?
Randy Sugianto 'Yuku'
La seule question qui reste est pourquoi vous dérangeriez-vous?
Warpzit
@Warpzit la plus grande question devrait être: Pourquoi un développeur ne s'embêtera-t-il pas avec toute cette confusion?
Amit
@Amit parce qu'il s'est rendu compte qu'Android est différent de Java et pour travailler avec Android, il doit utiliser les outils proposés.
Warpzit
2
@Warpzit Sa seule question est " Android peut-il comprendre java 7? " L'ignorance n'est jamais une solution / réponse ...
Amit
12

À partir du SDK Android v15, avec Eclipse 3.7.1, Java 7 n'est pas pris en charge pour le développement Android. La définition de la compatibilité source sur 1.7 impose de définir la compatibilité du fichier .class généré sur 1.7, ce qui entraîne l'erreur suivante du compilateur Android:

Android nécessite le niveau de conformité du compilateur 5.0 ou 6.0. Trouvé «1.7» à la place. Veuillez utiliser les outils Android> Corriger les propriétés du projet.

Hosam Aly
la source
5

Pour développer la réponse ci-dessus de @KennyTM, si vous ciblez la version 4.0.3 et supérieure ( minSdkVersion = 15 ), vous pouvez utiliser les API cachées en ajoutant quelques classes au SDK android.jar de votre cible.

Une fois que vous faites cela, vous pouvez utiliser try-with-resources sur n'importe quel Closeable, ainsi qu'implémenter AutoCloseable dans vos propres classes.

J'ai créé un zip contenant les sources et les binaires de toutes les classes qui devaient être modifiées dans android.jar pour rendre ces API disponibles. Il vous suffit de le décompresser et d'ajouter les binaires à votre
android-sdk / plates-formes / android-NN / android.jar

Vous pouvez le télécharger ici: http://db.tt/kLxAYWbr

Il faut également noter que, au cours des deux derniers mois, Elliott Hughes a fait quelques commits à l'arbre Android: parachevées AutoCloseable , ajouté SafeVarargs , API divers non masqués , fixe constructeur protégé de Throwable et un support supplémentaire pour la version 51 fichiers de classe dx . Donc, il y a enfin des progrès en cours.

Edit (avril 2014):

Avec la sortie du SDK 19, il n'est plus nécessaire de patcher android.jar avec les API supplémentaires.

La meilleure méthode pour utiliser try-with-resources dans Android Studio pour une application qui cible la version 4.0.3 et supérieure ( minSdkVersion = 15 ) consiste à ajouter ce qui suit compileOptionsà votre 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 se plaindra du fait que try-with-resources ne peut pas être utilisé avec ce niveau d'API, mais mon expérience est que c'est possible. Le projet sera construit et exécuté sans problème sur les appareils avec 4.0.3 et plus. Je n'ai rencontré aucun problème avec cela, avec une application qui a été installée sur plus de 500 000 appareils.

Erreur Android Studio

Pour ignorer cet avertissement, ajoutez ce qui suit à votre lint.xml:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>
Nuno Cruces
la source
1
Je trouve intéressant que l'avertissement de code Android Studio indique que try-with-resources est nouveau dans l'API 13 et que je devrais l'utiliser. Bien que vous n'ayez pas le temps de tester si cela fonctionne correctement.
Daniel Ryan
1

Il semble que faire fonctionner cela avec une fourmi pure est un peu un kludge.

Mais cela a fonctionné pour moi: http://www.informit.com/articles/article.aspx?p=1966024

mako
la source
1
J'ai longtemps cherché ça. Pour éviter les problèmes aux gens en filtrant l'article, vous devrez modifier la ligne `<property name =" java.source "value =" 1.5 "/>` dans le fichier build.xml fourni par Android (et non celui de votre projet!). Pour moi, c'était dans /opt/android-sdk-update-manager/tools/ant/build.xml
Mateusz Kowalczyk
Non tu ne le fais pas. Vous pouvez remplacer ces propriétés avec custom_rules.xml, voir ma réponse ici: stackoverflow.com/a/24608415/194894
Flow
1

Pour utiliser les fonctionnalités de Java 7 dans le code généré par le système de construction basé sur la fourmi d'Android, placez simplement ce qui suit dans votre custom_rules.xmlrépertoire racine de vos projets:

custom_rules.xml:

<project name="custom_android_rules">
    <property name="java.target" value="1.7" />
    <property name="java.source" value="1.7" />
</project>
Couler
la source
0

Certaines personnes pourraient être intéressées par ce projet git que j'ai trouvé, qui semble permettre d'exécuter Java 7 sur Android. https://github.com/yareally/Java7-on-Android

Cependant, trop de risque si j'ajoute cela dans le projet actuel sur lequel je travaille. J'attendrai donc que Google prenne officiellement en charge Java 7.

Daniel Ryan
la source