Java 8 pour Android code plus propre avec expressions lambda

Les expressions lambda peuvent vous aider à supprimer le code standard de vos projets et à traiter facilement d'énormes quantités de données. Découvrez comment, avec cet aperçu approfondi, les fonctionnalités de Java 8 que vous pouvez commencer à utiliser dans vos projets Android dès aujourd'hui. 

Java 8 pour Android

Java 8, qui a fait ses débuts en mars 2014, a été un grand pas en avant pour le langage de programmation, en présentant une liste de fonctionnalités qui promettaient de rendre le codage en Java plus facile et plus concis que jamais..

Malheureusement, les développeurs Android n'ont pas senti les avantages de ces fonctionnalités pendant un moment, car Google a expérimenté l'intégration de Java 8 sur la plate-forme Android via Jack (Kit de compilateur Java Android) avant de rendre obsolète Jack au profit de la prise en charge native de Java 8 dans Android Studio..

Maintenant, avec la sortie d'Android Studio 3.0, nous avons enfin une version de la chaîne d'outils Android qui prend en charge de manière intégrée certaines des fonctionnalités les plus importantes de Java 8..

Dans cette série, je vais vous montrer comment supprimer une tonne de code standard de vos projets, traiter facilement d'énormes quantités de données et même adopter un style plus fonctionnel dans votre programmation Java avec Java 8. Nous serons jetter un regard en profondeur sur les fonctionnalités de Java 8 que vous pouvez commencer à utiliser dès aujourd'hui.

Lorsque vous aurez terminé cette série, vous serez prêt à utiliser toutes les fonctionnalités Java 8 suivantes dans vos projets Android:

  • expressions lambda
  • références de méthodes
  • méthodes par défaut
  • méthodes d'interface statique
  • annotations de type
  • annotations répétées
  • interfaces fonctionnelles
  • l'API Stream

Dans ce premier article, nous allons examiner la fonctionnalité qui a généré le plus de buzz lors de la première sortie de Java 8 et qui pourrait faire toute la différence pour les développeurs Android: expressions lambda.

Préparer votre environnement de développement

Avant de pouvoir commencer à utiliser tout Java 8, vous devez vous assurer que votre environnement de développement est configuré pour prendre en charge cette version de Java..

Si Java 8 n'est pas déjà installé sur votre ordinateur, vous devez télécharger la dernière version de JDK8 et mettre à jour le chemin d'accès JDK d'Android Studio afin qu'il soit dirigé vers le package JDK8:

  • Lancer Android Studio.
  • Sélectionner Fichier> Structure du projet… depuis la barre d'outils Android Studio.
  • Mettre à jour le JDK Localisation champ de sorte qu'il pointe sur votre paquet JDK8 récemment téléchargé.

Si vous ne savez pas quelle version de Java que vous avez installée, vous pouvez vérifier en ouvrant une fenêtre de terminal (si vous êtes un utilisateur Mac) ou une invite de commande (si vous êtes sous Windows), puis en exécutant la procédure suivante. commander:

version java

Si elle retourne à la version 1.8 ou supérieure, alors vous êtes prêt à partir!

Vous devez également installer Android Studio 3.0 Preview 1 ou une version ultérieure. Toutefois, pour réduire les risques de bogues et autres comportements étranges, il est recommandé d’installer la dernière version d’Android Studio 3.0, qu’il s’agisse d’une version bêta, d’un aperçu ou. idéalement, une version stable d'Android Studio 3.0 (qui n'était pas encore disponible au moment de la rédaction). 

Ensuite, vous devrez apporter quelques modifications à votre projet. build.gradle des dossiers. Généralement, il vous suffit d’ajouter quelques lignes de code indiquant que ce projet doit générer du bytecode Java 8. Toutefois, si vous avez déjà expérimenté les fonctionnalités de Java 8 avec le compilateur Jack ou le projet Retrolambda, vous devez désactiver ces outils avant que votre projet puisse utiliser le support Java 8 amélioré et amélioré fourni par la chaîne d'outils par défaut d'Android..

Dans les sections suivantes, je vais vous montrer comment activer le support Java 8 et comment désactiver Retrolambda et Jack, si nécessaire..

Ajout de la prise en charge de Java 8 à un nouveau projet

En supposant que vous n’ayez pas précédemment activé Jack ou ajouté Retrolambda en tant que dépendance de projet, la première étape consiste à ouvrir votre projet. build.gradle fichier et assurez-vous que vous utilisez la version 3.0.0-alpha1 (ou supérieure) du plug-in Gradle for Android:

buildscript repositories google () jcenter () dépendances classpath 'com.android.tools.build:gradle:3.0.0-alpha6'

Ensuite, ouvrez chaque niveau de module build.gradle fichier dans lequel vous souhaitez utiliser les fonctionnalités de Java 8 et définir le niveau de langue du code source et la version du bytecode Java généré à JavaVersion.VERSION_1_8:

android compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runer. compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Si vous migrez de Jack

Le compilateur Jack est peut-être obsolète, mais tant qu'il est activé, votre projet utilisera le support Java 8 fourni par Jack, plutôt que celui fourni par la chaîne d'outils par défaut d'Android..

Utiliser un outil obsolète n’est jamais une bonne idée, mais il existe quelques raisons supplémentaires pour lesquelles vous devriez migrer depuis le compilateur Jack, si vous ne l’avez pas déjà fait..

Tout d'abord, Jack peut prendre en charge un sous-ensemble de fonctionnalités Java 8, mais contrairement à l'ensemble d'outils par défaut, il ne prend pas en charge les bibliothèques tierces utilisant ces fonctionnalités. Ainsi, en utilisant Jack, vous limitez immédiatement vos options en matière de bibliothèques tierces..

Deuxièmement, le compilateur Jack prend le code Java et le convertit directement en dex, sans produire de code intermédiaire intermédiaire. Tant que Jack est activé, vous ne pourrez utiliser aucun des outils qui dépendent de cette sortie intermédiaire, tels que les processeurs d'annotation et les analyseurs de code intermédiaire..

Pour désactiver le compilateur Jack, ouvrez votre module build.gradle déposer et supprimer le jackOptions section, mais assurez-vous de quitter le compilerOptions bloc intact:

android compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26 targetSdkVersion 26 versionCode 1 versionName "1.0" // Supprime la totalité de la section jackOptions // jackOptions jackOptions enabled. test.runner.AndroidJUnitRunner "// Ne supprime pas la section compileOptions // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Si vous migrez de Retrolambda

Semblable à Jack, Retrolambda ne prend pas en charge les bibliothèques tierces utilisant les fonctionnalités du langage Java 8. Si votre projet est configuré pour utiliser le plug-in Retrolambda, vous devez le supprimer pour que votre projet puisse revenir à la chaîne d'outils par défaut..

Ouvrez votre projet build.gradle déposer et supprimer Retrolambda en tant que dépendance de projet:

 dependencies classpath 'com.android.tools.build:gradle:3.0.0-beta2' // Supprime la ligne suivante // classpath 'me.tatarka: gradle-retrolambda: 3.7.0'

Ensuite, supprimez le plugin Retrolambda de chacun de vos modules de niveau module. build.gradle des dossiers:  

apply plugin: 'com.android.application' // Supprime la ligne suivante // // applique le plugin: 'me.tatarka.retrolambda' android … // Ne supprimez pas le bloc compileOptions! // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Testez votre support Java 8

Le moyen le plus simple de vérifier que votre projet peut maintenant prendre en charge Java 8 est d'écrire une expression lambda rapide et de voir si votre projet est toujours compilé..

Ajoutez un bouton à votre interface utilisateur (ou utilisez un bouton déjà existant), puis implémentez une onClickListener pour ce bouton, en utilisant une expression lambda. Ne vous inquiétez pas si le code suivant n'a pas beaucoup de sens, il le fera d'ici la fin de cet article.!

importer android.support.v7.app.AppCompatActivity; importer android.os.Bundle; importer android.widget.Button; importer android.view.View; importer android.widget.Toast; Classe publique MainActivity étend AppCompatActivity @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); // Implémente onClickListener à l'aide d'une expression lambda // Button button = (Button) findViewById (R.id.button); if (button! = null) button.setOnClickListener (View View) -> Toast.makeText (this, "J’ai été écrit en Java 8!", Toast.LENGTH_LONG) .show ()); 

Vérifiez que votre projet est toujours compilé, soit en sélectionnant Sync dans la bannière qui apparaît ou en sélectionnant Outils> Android> Synchroniser un projet avec des fichiers Gradle depuis la barre d'outils Android Studio.

Si Android Studio ne génère aucune erreur, vous êtes prêt à utiliser toutes les fonctionnalités que nous avons énumérées au début de cet article, y compris les expressions lambda.!

Pourquoi les expressions lambda sont-elles si importantes??

Les expressions lambda constituaient sans conteste la plus grande nouveauté de Java 8 et peuvent avoir une énorme impact sur la quantité de code passe-partout que vous devez écrire pour créer à peu près n'importe quelle application Android.

Essentiellement, une expression lambda représente une fonction qui n'appartient à aucune classe et que vous pouvez passer facilement, puis exécuter à la demande..

Cette fonctionnalité supprime une frustration de longue date vécue par de nombreux développeurs Android avec Java: en tant que langage orienté objet, la transmission de blocs de code a toujours senti plus difficile que cela ne devrait être. Par exemple, si vous voulez créer un nouveau thread, puis lui transmettre du code, vous devez généralement instancier un thread avec une implémentation anonyme de l'interface Runnable. Cela demande beaucoup de travail de passer du code! En fournissant un moyen simple de passer d'une fonction à une méthode, les expressions lambda peuvent potentiellement simplifier certaines des tâches les plus courantes que vous effectuerez en tant que développeur Android..

Les expressions Lambda constitueront également un atout de choix pour tous les développeurs Java qui souhaitent adopter une approche plus fonctionnelle de leur programmation. Avant Java 8, le codage dans un style fonctionnel obligeait inévitablement à écrire beaucoup de code standard, mais maintenant que vous pouvez transmettre des fonctions à l'aide d'expressions lambda, l'écriture de votre code Java d'une manière moins orientée objet ne doit plus impliquer écrire une tonne de cours anonymes.

Comment créer une expression Lambda?

Vous créez une expression lambda en utilisant la syntaxe suivante:

(argument) -> expression body

L'opérateur de flèche est assez explicite, mais les règles sur la manière de structurer l'argument et l'expression du lambda peuvent varier en fonction de l'objectif recherché, explorons donc ces deux éléments plus en détail..

L'argument

L'argument est un ou plusieurs paramètres, qui sont presque toujours entre parenthèses. Même si votre expression lambda ne contient aucun paramètre, vous devrez quand même fournir des parenthèses vides, par exemple:

() -> System.out.println ("Cette expression lambda n'a pas de paramètre");

L'exception à cette règle est lorsque votre méthode a un seul paramètre avec son type inféré, auquel cas vous pouvez omettre les parenthèses:

textView.setOnLongClickListener (event -> System.out.println ("clic long"));

Vous pouvez utiliser plusieurs paramètres dans votre argument en séparant chaque paramètre par une virgule:

(paramètre1, paramètre2) -> System.out.println ("Paramètres:" + paramètre1 + "," + paramètre2);

L'inférence de type est possible dans lambdas, vous pouvez donc généralement omettre le type de données de votre argument. Cependant, si le compilateur ne peut pas déduire le type de données, vous devrez alors ajouter le type devant vos paramètres:

 Bouton bouton = (Bouton) findViewById (R.id.button); if (button! = null) button.setOnClickListener ((Affichage)) -> Log.d ("debug", "Bouton cliqué")); 

Le corps d'expression

Le corps de l'expression est le code que vous souhaitez exécuter, qui peut être une expression unique ou plusieurs lignes de code. Si vous souhaitez exécuter plusieurs lignes, vous devez créer un bloc d'instructions en entourant cette section de votre code avec des accolades:

Bouton bouton = (Bouton) findViewById (R.id.button); button.setOnClickListener (view -> Log.d ("debug", "le bouton a été cliqué"); Toast.makeText (this, "J’ai été écrit en Java 8!", Toast.LENGTH_LONG) .show ();

Si votre expression renvoie une valeur, elle doit être renvoyée avec une instruction return, par exemple:

(paramètre1) -> System.out.println ("Paramètre:" + paramètre1); renvoyer "valeur de retour"; 

Utilisation d'expressions lambda dans vos applications Android

Maintenant, nous avons un aperçu des différentes manières de structurer une expression lambda. Voyons quelques-uns des scénarios les plus courants dans lesquels vous pouvez utiliser des expressions lambda dans votre travail de développement Android..

Lambdas pour la gestion d'événements

Votre application Android typique doit pouvoir répondre à un large éventail d'événements de saisie utilisateur. Les expressions lambda peuvent simplifier la gestion de ces événements..

Dans le code suivant, nous utilisons une classe anonyme pour créer une instance de onClickListener avec une dérogation sur clic méthode. Les chances sont, vous avez écrit ce genre de code innombrable fois.

Bouton bouton = (Bouton) findViewById (R.id.button); button.setOnClickListener (nouvelle View.OnClickListener () @Override public void onClick (Affichage) doQuelque chose ();;

En réécrivant le code ci-dessus avec une expression lambda, nous pouvons supprimer tous les éléments suivants:

  • l'instanciation de classe: new View.OnClickListener ()
  • le modificateur d'accès, le nom de la méthode et le type: public void onClick (Afficher la vue)
  • et les types de paramètres, de sorte que vous n'avez pas à écrire Voir la vue

Cela signifie que nous pouvons implémenter exactement la même fonctionnalité, en utilisant une seule ligne:

button.setOnClickListener (vue -> quelque chose ());

Lambdas pour le multithreading

Le multithreading est un autre scénario courant dans lequel les expressions lambda peuvent vous aider à écrire du code plus propre. Par défaut, Android possède un seul thread d'interface utilisateur (interface utilisateur) chargé de gérer toutes les interactions utilisateur, de distribuer les événements aux widgets d'interface utilisateur appropriés et de modifier l'interface utilisateur. Dès que vous bloquez ce thread d'interface utilisateur avec des opérations longues ou intensives, votre application ne répond plus et peut même déclencher le dialogue ANR (Application Not Responding) d'Android. Ainsi, la création de threads supplémentaires et l'affectation de code à exécuter sur ces threads constituent souvent un élément essentiel du développement Android..

Avant Java 8, pour que le code soit exécuté sur un thread supplémentaire, vous deviez créer une classe anonyme qui implémentait la Runnable interface:

Runnable r = new Runnable () @Override public void run () System.out.println ("Mon runnable"); ; Fil de fil = nouveau fil (r); thread.start ();

Alternativement, vous pouvez instancier un nouveau thread avec une implémentation anonyme du Runnable interface:

Thread thread = new Thread (new Runnable () @Override public void run () System.out.println ("Mon runnable");); thread.start ();

Le remplacement de cette classe anonyme par une expression lambda peut rendre cette tâche fréquemment exécutée beaucoup plus concis:

Runnable r = () -> System.out.println ("Mon runnable"); ; // Démarrer le nouveau thread // new Thread (r) .start ();

Enfin, si vous utilisez la bibliothèque RxJava ou RxAndroid, vous pouvez utiliser des expressions lambda pour vous aider à créer des observables..

Ici, nous créons un simple Observable qui émet la chaîne hello worldà tous ses Observateurs:

Observable.just ("Hello, world!") .Subscribe (nouvelle Action1() @Override public void call (String s) Log.d (TAG, s); );

Utiliser une expression lambda vous permet de remplacer tout cela Action1 code avec une seule ligne:

Observable.just ("Hello, world!") .Subscribe (s -> Log.d (TAG, s));

Utilisation d’expressions lambda dans votre Vrai vie Code

Après avoir lu toute la théorie derrière une nouvelle fonctionnalité, le prochain défi est de prendre l'habitude de en utilisant cette nouvelle fonctionnalité. Cela peut être particulièrement difficile avec quelque chose comme les lambdas, qui sont conçus pour être utilisés à la place du code habituel, car il est toujours tentant de se contenter de ce que vous savez..

Android Studio dispose de quelques fonctionnalités qui peuvent vous aider à donner le dernier coup de pouce pour remplacer un code familier mais simpliste par de nouvelles expressions lambda brillantes..

La première fonctionnalité est le menu des actions d'intention d'Android Studio, qui permet de convertir automatiquement toute classe anonyme compatible en expression lambda équivalente. C'est parfait si vous ne savez pas comment écrire un morceau de code particulier dans un format lambda: écrivez-le simplement, puis utilisez la fonction de conversion automatique du menu Action intentionnelle..

Pour convertir automatiquement une classe anonyme en une expression lambda:

  • Placez votre curseur sur la classe anonyme et Android Studio doit afficher une info-bulle vous informant qu'il peut convertir cette section de code en une expression lambda..
  • Appuyez sur votre Mac Alt / Option-Entrée clés, ou utilisez le Alt-Enter raccourci si vous êtes un utilisateur Windows ou Linux.
  • Sélectionnez le Remplacer par lambda option du menu contextuel.


Vous pouvez également utiliser l'outil d'inspection d'Android Studio pour signaler chaque classe anonyme que vous pourriez potentiellement remplacer par une expression lambda, dans l'ensemble de votre projet. Vous pouvez ensuite réécrire manuellement chaque classe anonyme ou laisser la fonction de conversion automatique d'Android Studio vous montrer comment procéder..

Pour mettre en évidence toutes les classes anonymes qu'Android Studio pourrait potentiellement remplacer par une expression lambda:

  • Sélectionner Analyser> Exécuter l'inspection par nom depuis la barre d'outils Android Studio.
  • Dans le popup qui apparaît, commencez à taper Le type anonyme peut être remplacé par lambda, puis sélectionnez cette option quand elle apparaît dans le menu déroulant.


  • Dans la fenêtre suivante, sélectionnez Projet complet pour marquer chaque classe anonyme de votre projet. Vous pouvez également spécifier des modules ou des fichiers individuels sur lesquels Android Studio doit exécuter cette inspection..
  • Cliquez sur D'accord.
  • Sélectionner Analyser> Inspecter le code depuis la barre d'outils Android Studio.

Le volet Résultats de l'inspection doit maintenant apparaître et afficher une liste de toutes les classes anonymes que vous pouvez remplacer par une expression lambda. Pour examiner de plus près une classe anonyme, il suffit de double-cliquez cette classe dans le Résultats d'inspection fenêtre, et Android Studio ouvrira le fichier et vous mènera à la ligne exacte contenant cette classe anonyme.

Pour remplacer la classe anonyme sélectionnée par une expression lambda, donnez le Remplacer par lambda bouton un clic.


Si Android Studio n'ouvre pas automatiquement la fenêtre Résultats de l'inspection, vous pouvez la lancer manuellement en sélectionnant Affichage> Fenêtres d'outils> Résultats de l'inspection depuis la barre d’outils Android Studio. Si les résultats d'inspection ne pas apparaissent dans le Fenêtre d'outil sous-menu, vous devrez peut-être sélectionner Analyser> Inspecter le code… à partir de la barre d'outils Android Studio.

Test des expressions lambda

Malgré les nombreux avantages offerts par les expressions lambda, vous devez être conscient d'un inconvénient majeur avant de les ajouter à votre code. Comme les lambdas n'ont pas de nom, vous ne pouvez pas les appeler directement à partir de votre code de test. Par conséquent, l'ajout d'un grand nombre de lambdas à votre projet peut rendre le test plus difficile..

Idéalement, vos expressions lambda devraient être trop simples pour être dissociées. Par conséquent, être incapable de les tester à l'unité ne devrait pas être un problème trop important. Cependant, si vous avez besoin de tester un lambda, vous pouvez toujours le traiter comme une méthode privée et tester le résultat final. résultat, plutôt que le lambda lui-même. Alternativement, vous pouvez refactoriser l'expression lambda dans sa propre méthode, de sorte que vous puissiez la référencer directement et donc la tester normalement..  

Conclusion

Dans ce premier article sur les fonctionnalités du langage Java 8, nous avons expliqué comment configurer vos projets Android pour prendre en charge Java 8 et réduire le code standard en remplaçant les classes anonymes par des expressions lambda.. 

Dans le prochain article, je vais vous montrer comment couper encore plus de code de vos projets Android en combinant des expressions lambda avec des références de méthodes et comment améliorer vos interfaces avec des méthodes d'interface par défaut et statiques..

En attendant, consultez quelques-uns de nos autres articles sur le développement d'applications Android.!