Java 8 pentru Android cod mai curat cu expresii Lambda

Expresiile Lambda vă pot ajuta să eliminați codul boilerplate din proiectele dvs. și să procesați cu ușurință cantități uriașe de date. Vedeți cum puteți să începeți să utilizați astăzi în proiectele Android aplicațiile Java 8 în profunzime. 

Java 8 pentru Android

Java 8, care a debutat în martie 2014, a reprezentat un mare pas înainte pentru limba de programare, introducând o listă de caracteristici care promiteau ca codarea în Java să fie mai ușoară și mai concisă decât oricând.

Din păcate, dezvoltatorii Android nu ar simți oarecum beneficiile acestor funcții, deoarece Google a experimentat introducerea Java 8 pe platforma Android prin Jack (Java Android Compiler Kit) înainte de a-l deprima pe Jack în favoarea sprijinirii Java 8 în Android Studio.

Acum, odată cu lansarea versiunii Android Studio 3.0, avem în sfârșit o versiune a instrumentului Android care are suport integrat pentru unele dintre cele mai importante caracteristici ale Java 8.

În această serie, vă voi arăta cum să eliminați o cantitate de cod de boilerplate din proiectele dvs., să procesați cu ușurință cantități uriașe de date și chiar să îmbrățișați un stil mai funcțional în programarea Java cu Java 8. Vom fi luând o privire detaliată asupra caracteristicilor Java 8 pe care le puteți utiliza astăzi.

În momentul în care ați finalizat această serie, veți fi gata să utilizați toate celelalte caracteristici Java 8 din proiectele Android:

  • expresii lambda
  • referințe de referință
  • metode implicite
  • metodele de interfață statică
  • tip adnotări
  • repetarea adnotărilor
  • interfețe funcționale
  • API-ul Stream

În această primă postare, vom examina caracteristica care a generat cel mai mult buzz când a fost lansată pentru prima dată Java 8 și care are potențialul de a aduce cea mai mare importanță dezvoltatorilor Android: expresii lambda.

Pregătirea mediului de dezvoltare

Înainte de a începe să utilizați orice Caracteristicile Java 8, trebuie să vă asigurați că mediul dvs. de dezvoltare este configurat pentru a sprijini această versiune de Java.

Dacă nu aveți deja instalat Java 8, va trebui să descărcați cea mai recentă versiune JDK8 și să actualizați calea JDK pentru Android Studio, astfel încât să indice pachetul JDK8:

  • Lansați Android Studio.
  • Selectați Fișier> Structura proiectului ... din bara de instrumente Android Studio.
  • Actualizați Locația JDK astfel încât să se îndrepte spre noul pachet JDK8 descărcat.

Dacă nu sunteți sigur ce versiune de Java ați instalat, puteți verifica dacă deschideți o fereastră Terminal (dacă sunteți un utilizator Mac) sau o Command Prompt (dacă sunteți pe Windows) și apoi executați următoarele comanda:

java -versiune

Dacă se întoarce construi 1.8 sau mai mult, atunci ești bine să pleci!

De asemenea, trebuie să aveți instalat versiunea Android Studio 3.0 Preview 1 sau o versiune superioară, deși pentru a reduce șansele de a întâlni bug-uri și alte comportamente ciudate, este recomandat să instalați cea mai recentă versiune de Android Studio 3.0 - fie că este vorba de beta sau de previzualizare, în mod ideal, o versiune stabilă de Android Studio 3.0 (care încă nu era disponibil la momentul redactării). 

Apoi, va trebui să faceți niște modificări în proiectul dvs. build.gradle fișiere. De obicei, va trebui doar să adăugați câteva linii de cod care specifică faptul că acest proiect ar trebui să genereze Java 8 bytecode. Cu toate acestea, dacă ați experimentat anterior cu funcțiile Java 8 utilizând compilatorul Jack sau popularul proiect Retrolambda, va trebui să dezactivați aceste instrumente înainte ca proiectul dvs. să poată utiliza noul suport îmbunătățit Java 8 furnizat de setul implicit de instrumente Android.

În secțiunile următoare, vă vom arăta cum să activați suportul Java 8 și cum să dezactivați Retrolambda și Jack, dacă este necesar.

Adăugarea suportului Java 8 la un nou proiect

Presupunând că nu ați activat anterior Jack sau adăugați Retrolambda ca dependență de proiect, primul pas este deschiderea nivelului de proiect build.gradle și asigurați-vă că utilizați versiunea 3.0.0-alpha1 (sau o versiune superioară) a pluginului Gradle pentru Android:

buildscript repositories google () jcenter () dependențe classpath 'com.android.tools.build:gradle:3.0.0-alpha6'

Apoi, deschideți fiecare nivel de modul build.gradle fișierul în care doriți să utilizați funcțiile Java 8 și setați nivelul de limbă al codului sursă și versiunea Java bytecode generată la JavaVersion.VERSION_1_8:

android compileSdkVersion 26 buildToolsVersion "26.0.1" implicitConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // Adăugați următorul bloc // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Dacă migrați de la Jack

Compilatorul Jack poate fi depreciat, dar atâta timp cât este activat, proiectul tău va utiliza suportul Java 8 furnizat de Jack, mai degrabă decât suportul furnizat de setul de instrumente Android implicit.

Utilizarea unui instrument depreciat nu este niciodată o idee bună, dar există și câteva motive suplimentare pentru care ar trebui să migrați de la compilatorul Jack, dacă nu ați făcut-o deja.

În primul rând, Jack poate să susțină un subset de funcții Java 8, dar, spre deosebire de setul de instrumente implicit, nu suportă biblioteci terțe care utilizează aceste funcții, prin utilizarea lui Jack limitați imediat opțiunile atunci când vine vorba de biblioteci terțe.

În al doilea rând, compilatorul Jack ia codul Java și îl convertește direct în dex, fără a produce niciun octet intermediar. Atâta timp cât Jack este activat, nu veți putea utiliza niciunul dintre instrumentele care se bazează pe această ieșire intermediară, cum ar fi procesoarele de adnotări și analizoarele bytecode.

Pentru a dezactiva compilatorul Jack, deschideți nivelul modulului build.gradle fișier și eliminați jackOptions secțiune, dar asigurați-vă că părăsiți compileOptions bloc intact:

android compileSdkVersion 26 buildToolsVersion "26.0.1" implicitConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26 targetSdkVersion 26 versionCode 1 versionName "1.0" // Eliminați întreaga secțiune jackOptions // jackOptions enabled true testInstrumentationRunner "android.support. test.runner.AndroidJUnitRunner "// Nu eliminați secțiunea compileOptions // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Dacă migrați din Retrolambda

Similar cu Jack, Retrolambda nu suportă biblioteci terțe care utilizează caracteristici de limbă Java 8. Dacă proiectul dvs. este configurat să utilizeze pluginul Retrolambda, atunci trebuie să eliminați acest plugin, astfel încât proiectul dvs. să poată reveni la setul implicit de instrumente.

Deschideți nivelul proiectului build.gradle fișier și eliminați Retrolambda ca dependență de proiect:

 dependencies classpath 'com.android.tools.build:gradle:3.0.0-beta2' // Eliminați următoarea linie // classpath 'me.tatarka: gradle-retrolambda: 3.7.0'

Apoi, eliminați pluginul Retrolambda de la fiecare dintre modulele la nivel build.gradle fișiere:  

aplicați pluginul: 'com.android.application' // Eliminați următorul rând // apply plugin: 'me.tatarka.retrolambda' android ... // Nu ștergeți compileOptions bloc! // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8

Testați-vă suportul Java 8

Cea mai ușoară modalitate de a verifica dacă proiectul dvs. poate suporta acum Java 8 este să scrieți o expresie lambda rapidă și să vedeți dacă proiectul dvs. încă se compilează.

Adăugați un buton la interfața dvs. de utilizator (sau folosiți un buton care există deja) și apoi implementați un onClickListener pentru acest buton, folosind o expresie lambda. Nu vă faceți griji dacă următorul cod nu are prea mult sens acum - va fi până la sfârșitul acestui articol!

import șiroid.support.v7.app.AppCompatActivity; import android.os.Bundle; import șiroid.widget.Button; import șiroid.view.View; importă android.widget.Toast; clasa publica MainActivity extinde AppCompatActivity @Override protejat void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); // Implementați onClickListener folosind o expresie lambda // Buton buton = (buton) findViewById (R.id.button); dacă (buton! = null) button.setOnClickListener ((Vizualizare vizualizare) -> Toast.makeText (aceasta a fost "Am scris în Java 8!", Toast.LENGTH_LONG) .show ()); 

Verificați dacă proiectul dvs. încă se compilează, fie prin selectarea Sincronizare din bannerul care apare sau selectând Instrumente> Android> Proiect de sincronizare cu fișiere Gradle din bara de instrumente Android Studio.

Dacă Android Studio nu aruncă nicio eroare, atunci sunteți gata să începeți să utilizați toate funcțiile pe care le-am enumerat la începutul acestui articol, inclusiv expresii lambda!

De ce sunt atât de importante expresiile Lambda?

Expresiile Lambda au fost cu ușurință noua caracteristică nouă a programului Java 8 și pot avea o imens impact asupra cantității de cod de boilerplate pe care trebuie să-l scrieți atunci când creați aproape orice aplicație Android.

În esență, o expresie lambda reprezintă o funcție care nu aparține niciunei clase și că puteți trece ușor și apoi executa la cerere.

Această caracteristică elimină o frustrare de lungă durată pe care mulți dezvoltatori Android l-au experimentat cu Java: ca limbă orientată pe obiecte, trecerea în jurul blocurilor de coduri mereu era mai dificil decât ar fi trebuit. De exemplu, dacă doriți să creați un fir nou și apoi să transmiteți un anumit cod la acel fir, atunci ar trebui să instanțiați un fir cu o implementare anonimă a interfeței Runnable - care este mult de lucru doar pentru a trece un cod! Oferind o modalitate ușoară de a transmite o funcție unei metode, expresiile lambda au potențialul de a simplifica unele dintre cele mai frecvente sarcini pe care le veți realiza ca dezvoltator Android.

Expresiile Lambda vor fi, de asemenea, un plus de bun venit pentru orice dezvoltatori Java care doresc să adopte o abordare mai funcțională a programării lor. Înainte de Java 8, codarea într-un stil funcțional ar necesita în mod inevitabil să scrieți o mulțime de cod de boilerplate, dar acum că puteți trece funcții folosind expresii lambda, scrierea codului Java într-un mod mai puțin orientat pe obiecte nu trebuie să implice scriind o tona de clase anonime.

Cum creez o expresie Lambda?

Creați o expresie lambda utilizând următoarea sintaxă:

(argument) -> body expression

Operatorul săgeții este destul de auto-explicativ, dar regulile pentru modul în care ar trebui să structurați argumentul și expresia lambda pot varia în funcție de ceea ce încercați să realizați, prin urmare, să explorăm aceste două elemente în detaliu.

Argumentul

Argumentul este unul sau mai mulți parametri, care sunt aproape întotdeauna închise în paranteze. Chiar dacă expresia dvs. lambda nu are parametri, va trebui să furnizați în continuare paranteze goale, de exemplu:

() -> System.out.println ("Această expresie lambda nu are parametri");

Excepția la această regulă este atunci când metoda dvs. are un singur parametru cu tipul său dedus, caz în care puteți omite parantezele:

textView.setOnLongClickListener (eveniment -> System.out.println ("Long Click"));

Puteți utiliza mai mulți parametri în argumentul dvs., separând fiecare parametru cu o virgulă:

(parametru1, parametru2) -> System.out.println ("Parametrii:" + parametru1 + "," + parametru2);

Inferența de tip este posibilă în lambda, astfel încât, în general, puteți omite tipul de date din argumentul dvs. Cu toate acestea, dacă compilatorul nu poate deduce tipul de date, atunci va trebui să adăugați tipul în fața parametrului (lor):

 Buton buton = (buton) findViewById (R.id.button); dacă (butonul! = null) button.setOnClickListener ((Vizualizare vizualizare) -> Log.d ("debug", "Buton clicked")); 

Organismul de expresie

Organismul de expresie este codul pe care doriți să-l executați, care poate fi o singură expresie sau mai multe rânduri de cod. Dacă doriți să executați mai multe linii, atunci va trebui să creați un bloc de instrucțiuni prin înconjurarea acestei secțiuni a codului dvs. cu bretele curbate:

Buton buton = (buton) findViewById (R.id.button); buton.setOnClickListener (vezi -> Log.d ("debug", "Buton clicked"); Toast.makeText (aceasta a fost "Am scris în Java 8!", Toast.LENGTH_LONG) .show ();

Dacă expresia dvs. returnează o valoare, atunci trebuie returnată cu o declarație de returnare, de exemplu:

(parametru1) -> System.out.println ("Parametru:" + parametru1); retur "valoarea returnata"; 

Folosind expresii Lambda în aplicațiile Android

Acum avem o privire de ansamblu asupra diferitelor moduri în care puteți structura o expresie lambda, să aruncăm o privire asupra unora dintre cele mai frecvente scenarii în care puteți utiliza expresii lambda în munca dvs. de dezvoltare Android.

Lambdas pentru manipularea evenimentelor

Aplicația dvs. tipică pentru Android trebuie să fie capabilă să răspundă la o gamă largă de evenimente de intrare de la utilizatori, iar expresiile lambda pot face acest eveniment mult mai simplu.

În codul următor, folosim o clasă anonimă pentru a crea o instanță de onClickListener cu o suprasarcină onClick metodă. Sunt șanse, ai scris un fel de cod nenumărat ori.

Buton buton = (buton) findViewById (R.id.button); butonul.setOnClickListener (noul View.OnClickListener () @Override public void onClick (Vizualizare vizualizare) doSomething (););

Prin rescrierea codului de mai sus cu o expresie lambda, putem elimina toate următoarele:

  • instanța de clasă: new View.OnClickListener ()
  • modificatorul de acces, numele metodei și tipul: public void onClick (vizualizare Vizualizare)
  • și tipurile de parametri, deci nu trebuie să scrieți Afișați vizualizarea

Aceasta înseamnă că putem implementa exact aceeași funcționalitate, utilizând o singură linie:

buton.setOnClickListener (vizualizare -> doSomething ());

Lambdas pentru Multithreading

Multithreading este un alt scenariu obișnuit în care expresiile lambda vă pot ajuta să scrieți un cod mai curat. În mod implicit, Android are un singur fir UI (interfața cu utilizatorul) care este responsabil pentru manipularea interacțiunii cu utilizatorul, expedierea evenimentelor la widgeturile UI corespunzătoare și modificarea interfeței cu utilizatorul. De îndată ce blocați acest thread UI cu orice operațiuni de lungă durată sau intensivă, aplicația va deveni nereușită și poate chiar să declanșeze dialogul ANR (Application Not Responding) din Android. Deci, crearea de fire adiționale și atribuirea unui cod pentru a rula pe aceste fire este adesea o parte esențială a dezvoltării Android.

Înainte de Java 8, atribuirea codului pentru a rula pe un fir suplimentar vă cere să creați o clasă anonimă care implementează runnable interfaţă:

Runnable r = nouă Runnable () @Override public void run () System.out.println ("runnable meu"); ; Thread thread = nou subiect (r); thread.start ();

Alternativ, ați putea instanțiza un fir nou cu o implementare anonimă a runnable interfaţă:

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

Înlocuirea acestei clase anonime cu o expresie lambda poate face această sarcină frecvent efectuată mult mai concis:

Se poate executa r = () -> System.out.println ("Runnable"); ; // Începeți noul thread // new Thread (r) .start ();

În cele din urmă, dacă utilizați biblioteca RxJava sau RxAndroid, puteți utiliza expresii lambda pentru a vă ajuta să creați observabile.

Aici, creăm un simplu Observabil care emite șirul de salut lumela toate observatorii:

Observable.just ("Bună ziua, lumea!") .Subscribe (acțiune nouă1() @Override apel public void (String s) Log.d (TAG, s); );

Folosirea unei expresii lambda vă permite să înlocuiți toate acestea Acțiunea 1 cod cu o singură linie:

Observable.just ("Buna ziua, lumea!") .Subscribe (s -> Log.d (TAG, s));

Folosind expresii Lambda în Viata reala Cod

După ce a citit toată teoria din spatele unei caracteristici noi, următoarea provocare este obiceiul de a deveni obișnuit utilizând această nouă caracteristică. Acest lucru poate fi deosebit de greu cu ceva de genul lambda, care sunt concepute pentru a fi utilizate în locul codului de boilerplate familiar, deoarece întotdeauna există ispita de a cădea pur și simplu pe ceea ce știi.

Android Studio are câteva caracteristici care vă pot ajuta să vă împingeți definitiv pentru a înlocui codul familiar, dar clunky, cu expresii strălucitoare lambda strălucitoare.

Prima caracteristică este meniul de acțiuni de intenții Android Studio, care poate converti automat orice clasă anonimă compatibilă în expresia lambda echivalentă. Acest lucru este perfect dacă nu sunteți sigur niciodată despre cum să scrieți o anumită bucată de cod într-un format lambda: pur și simplu scrieți-l ca de obicei și apoi utilizați funcția de auto-conversie a meniului de acțiune intent.

Pentru a converti automat o clasă anonimă într-o expresie lambda:

  • Plasați cursorul peste clasa anonimă, iar Android Studio ar trebui să afișeze un instrument care vă informează că poate converti această secțiune de cod într-o expresie lambda.
  • Apăsați pe Mac Alt / Option-Enter chei sau utilizați Alt-Enter dacă sunteți utilizator Windows sau Linux.
  • Selectează Înlocuiți cu lambda opțiune din meniul contextual.


Alternativ, puteți utiliza instrumentul de inspecție Android Studio pentru a semnala fiecare clasă anonimă pe care ați putea să o înlocuiți cu o expresie lambda, în întregul dvs. proiect. Apoi, puteți fie să rescrieți fiecare clasă anonimă manual fie să permiteți funcția de conversie automată Android Studio să vă arate cum se face.

Pentru a evidenția fiecare clasă anonimă pe care Android Studio ar putea să o înlocuiască cu o expresie lambda:

  • Selectați Analizați> Inspectați execuția după nume din bara de instrumente Android Studio.
  • În pop-ul care apare, începeți să tastați Tipul anonim poate fi înlocuit cu lambda, apoi selectați această opțiune când apare în meniul derulant.


  • În fereastra următoare, selectați Proiect întreg să semnalezi fiecare clasă anonimă în proiectul tău. Alternativ, puteți specifica module sau fișiere individuale în care Android Studio ar trebui să ruleze această inspecție.
  • Clic O.K.
  • Selectați Analizați> Inspectați codul din bara de instrumente Android Studio.

Panoul Rezultate de inspecție ar trebui să apară acum și să afișeze o listă a tuturor claselor anonime pe care le puteți înlocui cu o expresie lambda. Pentru a arunca o privire mai atentă la o clasă anonimă, pur și simplu dublu click această clasă în Rezultatele inspecției fereastra și Android Studio vor deschide fișierul și vă vor conduce la linia exactă care conține această clasă anonimă.

Pentru a înlocui clasa anonimă selectată curent cu o expresie lambda, dați Înlocuiți cu lambda clic pe un clic.


Dacă aplicația Android Studio nu deschide automat fereastra Rezultate de inspecție, puteți să o lansați manual selectând Vizualizare> Instrumente Windows> Rezultatele inspecției din bara de instrumente Android Studio. Dacă rezultatele inspecției nu apar în Instrumentul Windows sub-meniu, atunci este posibil să fie necesar să selectați Analizați> Inspectați codul ... din bara de instrumente Android Studio.

Testarea expresiilor Lambda

În ciuda numeroaselor avantaje pe care expresiile lambda le oferă, există un dezavantaj major pe care trebuie să îl cunoașteți înainte de a le adăuga la codul dvs. Din moment ce lambdas nu au un nume, nu le puteți apela direct din codul dvs. de testare, adăugând astfel un număr mare de lambda la proiectul dvs., poate face mai dificilă testarea.

În mod ideal, expresiile dvs. lambda ar trebui să fie prea simple pentru a se rupe, așadar imposibilitatea de a le testa unitatea nu ar trebui să fie prea mare pentru o problemă. Cu toate acestea, dacă aveți nevoie pentru a testa o lambda, atunci puteți trata întotdeauna ca o metodă privată și unitate de testare a rezultat, mai degrabă decât lambda însăși. Alternativ, ați putea refactoriza expresia lambda în propria sa metodă, astfel încât să o puteți referi direct și, prin urmare, să o testați ca în mod normal.  

Concluzie

În această primă postare despre caracteristicile limbajului Java 8, am analizat cum să configurați proiectele Android pentru a sprijini Java 8 și cum să reduceți codul boilerplate înlocuind clasele anonime cu expresii lambda. 

În următoarea postare, vă vom arăta cum să tăiați și mai mult cod din proiectele Android, combinând expresiile lambda cu referințe de metode și cum vă puteți îmbunătăți interfețele cu metode de interfață implicită și statică.

Între timp, verificați câteva dintre celelalte postări despre dezvoltarea aplicațiilor Android!

Cod