Le espressioni Lambda possono aiutarti a rimuovere il codice boilerplate dai tuoi progetti e ad elaborare enormi quantità di dati con facilità. Guarda come con questo sguardo approfondito sulle funzionalità di Java 8 che puoi iniziare a utilizzare nei tuoi progetti Android oggi.
Java 8, che ha debuttato nel lontano marzo 2014, è stato un grande passo avanti per il linguaggio di programmazione, introducendo un elenco di funzionalità che promettevano di rendere la codifica in Java più semplice e concisa che mai.
Sfortunatamente, gli sviluppatori di Android non sentiranno i benefici di queste funzionalità per un po ', mentre Google ha sperimentato l'introduzione di Java 8 sulla piattaforma Android tramite Jack (Java Android Compiler Kit) prima di deprecare Jack in favore del supporto di Java 8 in modo nativo in Android Studio.
Ora, con il rilascio di Android Studio 3.0, abbiamo finalmente una versione della toolchain Android che ha il supporto integrato per alcune delle funzionalità più importanti di Java 8.
In questa serie, ti mostrerò come rimuovere una tonnellata di codice boilerplate dai tuoi progetti, elaborare grandi quantità di dati con facilità e persino adottare uno stile più funzionale nella tua programmazione Java con Java 8. Saremo dare un'occhiata approfondita alle funzionalità di Java 8 che è possibile iniziare a utilizzare oggi.
Quando avrai completato questa serie, sarai pronto per utilizzare tutte le seguenti funzionalità di Java 8 nei tuoi progetti Android:
In questo primo post, esamineremo la funzione che ha generato il maggior numero di buzz quando Java 8 è stato rilasciato per la prima volta, e questo potrebbe potenzialmente fare la differenza per gli sviluppatori Android: espressioni lambda.
Prima di poter iniziare a usare qualunque Funzionalità Java 8, è necessario assicurarsi che il proprio ambiente di sviluppo sia configurato per supportare questa versione di Java.
Se non hai già installato Java 8, dovrai scaricare l'ultimo JDK8 e aggiornare il percorso JDK di Android Studio in modo che indichi il pacchetto JDK8:
Se non sei sicuro di quale versione di Java hai installato, puoi controllare aprendo una finestra di Terminale (se sei un utente Mac), o un Prompt dei comandi (se sei su Windows) e poi eseguendo quanto segue comando:
java -version
Se restituisce build 1.8 o superiore, allora sei a posto!
Avrai anche bisogno di avere Android Studio 3.0 Preview 1 o versione successiva, anche se per ridurre le possibilità di incontrare bug e altri strani comportamenti, ti consigliamo di installare l'ultima versione di Android Studio 3.0, sia che si tratti di una beta o di un'anteprima o, idealmente, una versione stabile di Android Studio 3.0 (che non era ancora disponibile al momento della scrittura).
Successivamente, dovrai apportare alcune modifiche al tuo progetto build.gradle
File. Di solito, devi solo aggiungere alcune righe di codice che specificano che questo progetto dovrebbe generare bytecode Java 8. Tuttavia, se hai già sperimentato le funzionalità di Java 8 utilizzando il compilatore Jack o il famoso progetto Retrolambda, dovrai disabilitare questi strumenti prima che il tuo progetto possa utilizzare il supporto Java 8 nuovo e migliorato fornito dalla toolchain predefinita di Android..
Nelle sezioni seguenti, ti mostrerò come abilitare il supporto per Java 8 e come disabilitare Retrolambda e Jack, se necessario.
Supponendo che tu non abbia precedentemente abilitato Jack o aggiunto Retrolambda come dipendenza del progetto, il primo passo è l'apertura del tuo progetto build.gradle
file e assicurandosi di utilizzare la versione 3.0.0-alpha1 (o successiva) del plugin Gradle per Android:
buildscript repositories google () jcenter () dependencies classpath 'com.android.tools.build:gradle:3.0.0-alpha6'
Quindi, apri ogni livello di modulo build.gradle
file in cui si desidera utilizzare le funzionalità di Java 8 e impostare il livello di lingua del codice sorgente e la versione del bytecode Java generato su 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.runner.AndroidJUnitRunner" // Aggiungi il seguente blocco // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
Il compilatore Jack può essere deprecato, ma finché è abilitato, il tuo progetto utilizzerà il supporto Java 8 fornito da Jack, piuttosto che il supporto fornito dalla toolchain predefinita di Android..
L'utilizzo di uno strumento deprecato non è mai una buona idea, ma ci sono alcuni ulteriori motivi per cui dovresti migrare dal compilatore Jack, se non lo hai già fatto.
In primo luogo, Jack può supportare un sottoinsieme di funzionalità di Java 8, ma a differenza della toolchain predefinita non supporta le librerie di terze parti che utilizzano queste funzionalità, quindi utilizzando Jack si limita immediatamente le opzioni quando si tratta di librerie di terze parti.
In secondo luogo, il compilatore Jack prende il codice Java e lo converte direttamente in dex, senza produrre alcun bytecode intermedio. Finché Jack è abilitato, non sarai in grado di utilizzare nessuno degli strumenti che si basano su questo output intermedio, come i processori di annotazione e gli analizzatori bytecode.
Per disabilitare il compilatore Jack, apri il tuo livello di modulo build.gradle
file e rimuovere il jackOptions
sezione, ma assicurati di lasciare il compileOptions
blocco intatto:
android compileSdkVersion 26 buildToolsVersion "26.0.1" defaultConfig applicationId "com.jessicathornsby.myapplication" minSdkVersion 26 targetSdkVersion 26 versionCode 1 versionName "1.0" // Rimuovi l'intera sezione jackOptions // jackOptions enabled true testInstrumentationRunner "android.support. test.runner.AndroidJUnitRunner "// Non rimuovere la sezione compileOptions // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
Simile a Jack, Retrolambda non supporta librerie di terze parti che utilizzano funzionalità di linguaggio Java 8. Se il tuo progetto è impostato per usare il plugin Retrolambda, allora dovresti rimuovere questo plugin in modo che il tuo progetto possa tornare alla toolchain predefinita.
Apri il tuo progetto a livello build.gradle
file e rimuovere Retrolambda come dipendenza del progetto:
dipendencies classpath 'com.android.tools.build:gradle:3.0.0-beta2' // Rimuovi la riga seguente // classpath 'me.tatarka: gradle-retrolambda: 3.7.0'
Quindi, rimuovi il plug-in Retrolambda da ogni livello di modulo build.gradle
File:
applica il plugin: 'com.android.application' // Rimuovi la seguente riga // applica il plugin: 'me.tatarka.retrolambda' android ... // Non elimina il blocco compileOptions! // compileOptions sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
Il modo più semplice per verificare che il tuo progetto possa ora supportare Java 8 è scrivere una rapida espressione lambda e vedere se il tuo progetto è ancora compilato.
Aggiungi un pulsante all'interfaccia utente (o utilizza un pulsante già esistente) e quindi implementa un onClickListener
per questo pulsante, usando un'espressione lambda. Non preoccuparti se il seguente codice non ha molto senso ora - lo sarà alla fine di questo articolo!
import android.support.v7.app.AppCompatActivity; importare android.os.Bundle; importa android.widget.Button; importa android.view.View; importare android.widget.Toast; public class MainActivity estende AppCompatActivity @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); // Implementa onClickListener utilizzando un'espressione lambda // Pulsante button = (Button) findViewById (R.id.button); if (button! = null) button.setOnClickListener ((Visualizza vista) -> Toast.makeText (questo, "Sono stato scritto in Java 8!", Toast.LENGTH_LONG) .show ());
Verifica che il tuo progetto sia ancora compilato, selezionando Sync dal banner che appare o selezionando Strumenti> Android> Sincronizza progetto con file Gradle dalla barra degli strumenti di Android Studio.
Se Android Studio non genera errori, sei pronto per iniziare a utilizzare tutte le funzionalità elencate all'inizio di questo articolo, incluse le espressioni lambda!
Le espressioni Lambda erano facilmente la nuova più grande funzionalità di Java 8 e possono avere un enorme impatto sulla quantità di codice boilerplate che devi scrivere quando crei praticamente qualsiasi app per Android.
Essenzialmente, un'espressione lambda rappresenta una funzione che non appartiene a nessuna classe e che puoi passare facilmente e quindi eseguire su richiesta.
Questa funzione rimuove una frustrazione di vecchia data che molti sviluppatori Android hanno sperimentato con Java: come linguaggio orientato agli oggetti, il passaggio di blocchi di codice ha sempre sentito più difficile di quanto dovrebbe essere. Ad esempio, se volessi creare un nuovo thread e poi passare del codice a quel thread, in genere dovresti creare un'istanza di un thread con un'implementazione anonima dell'interfaccia Runnable, che è molto lavoro solo per passare del codice! Fornendo un modo semplice per passare una funzione a un metodo, le espressioni lambda hanno il potenziale di semplificare alcune delle attività più comuni che svolgerete come sviluppatore Android.
Le espressioni Lambda saranno anche una gradita aggiunta per tutti gli sviluppatori Java che desiderano adottare un approccio più funzionale alla loro programmazione. Prima di Java 8, la codifica in uno stile funzionale richiederebbe inevitabilmente di scrivere un sacco di codice boilerplate, ma ora che è possibile passare le funzioni usando espressioni lambda, scrivere il codice Java in un modo meno orientato agli oggetti non deve implicare scrivere una tonnellata di classi anonime.
Si crea un'espressione lambda usando la seguente sintassi:
(argomento) -> corpo espressione
L'operatore della freccia è piuttosto auto-esplicativo, ma le regole su come dovresti strutturare l'argomento e l'espressione di lambda possono variare a seconda di cosa stai cercando di ottenere, quindi esploriamo questi due elementi in modo più dettagliato.
L'argomento è uno o più parametri, che sono quasi sempre racchiuso tra parentesi. Anche se l'espressione lambda non ha parametri, dovrai comunque fornire parentesi vuote, ad esempio:
() -> System.out.println ("Questa espressione lambda non ha parametri");
L'eccezione a questa regola è quando il tuo metodo ha un singolo parametro con il suo tipo inferito, nel qual caso puoi omettere le parentesi:
textView.setOnLongClickListener (event -> System.out.println ("Long Click"));
Puoi utilizzare più parametri nel tuo argomento, separando ogni parametro con una virgola:
(parametro1, parametro2) -> System.out.println ("Parametri:" + parametro1 + "," + parametro2);
L'inferenza di tipo è possibile in lambda, quindi puoi generalmente omettere il tipo di dati dal tuo argomento. Tuttavia, se il compilatore non può dedurre il tipo di dati, dovrai aggiungere il tipo davanti ai tuoi parametri:
Button button = (Button) findViewById (R.id.button); if (button! = null) button.setOnClickListener ((Visualizza vista) -> Log.d ("debug", "Button cliccato"));
Il corpo dell'espressione è il codice che si desidera eseguire, che può essere una singola espressione o più righe di codice. Se si desidera eseguire più righe, è necessario creare un blocco di istruzioni circondando questa sezione del codice con parentesi graffe:
Button button = (Button) findViewById (R.id.button); button.setOnClickListener (view -> Log.d ("debug", "Button cliccato"); Toast.makeText (questo, "Sono stato scritto in Java 8!", Toast.LENGTH_LONG) .show ();
Se la tua espressione restituisce un valore, deve essere restituito con un'istruzione return, ad esempio:
(parametro1) -> System.out.println ("Parametro:" + parametro1); restituire "valore di ritorno";
Ora abbiamo una panoramica dei vari modi in cui è possibile strutturare un'espressione lambda, diamo uno sguardo ad alcuni degli scenari più comuni in cui è possibile utilizzare espressioni lambda nel lavoro di sviluppo Android.
La tua tipica app per Android deve essere in grado di rispondere a una vasta gamma di eventi di input dell'utente, e le espressioni lambda possono rendere questo evento molto più semplice da gestire.
Nel codice seguente, stiamo usando una classe anonima per creare un'istanza di onClickListener
con un override al clic
metodo. È probabile che tu abbia scritto questo tipo di codice innumerevole volte.
Button button = (Button) findViewById (R.id.button); button.setOnClickListener (new View.OnClickListener () @Override public void onClick (Visualizza vista) doSomething (););
Riscrivendo il codice precedente con un'espressione lambda, possiamo rimuovere tutti i seguenti elementi:
nuovo View.OnClickListener ()
public void onClick (Visualizza vista)
Visualizza vista
Ciò significa che possiamo implementare esattamente la stessa funzionalità, utilizzando una singola riga:
button.setOnClickListener (view -> doSomething ());
Il multithreading è un altro scenario comune in cui le espressioni lambda possono aiutarti a scrivere codice più pulito. Per impostazione predefinita, Android ha un singolo thread dell'interfaccia utente (interfaccia utente) responsabile della gestione di tutte le interazioni dell'utente, della distribuzione degli eventi ai widget dell'interfaccia utente appropriati e della modifica dell'interfaccia utente. Non appena blocchi questo thread dell'interfaccia utente con operazioni di lunga durata o intense, la tua applicazione non risponderà più e potrebbe persino attivare la finestra di dialogo ANR (Applicazione non rispondente) di Android. Pertanto, la creazione di thread aggiuntivi e l'assegnazione di codice per l'esecuzione su tali thread è spesso una parte essenziale dello sviluppo di Android.
Prima di Java 8, l'assegnazione del codice per l'esecuzione su un thread aggiuntivo richiedeva la creazione di una classe anonima che implementa il codice Runnable
interfaccia:
Runnable r = new Runnable () @Override public void run () System.out.println ("My runnable"); ; Thread thread = new Thread (r); Thread.start ();
In alternativa, è possibile creare un'istanza di un nuovo thread con un'implementazione anonima del file Runnable
interfaccia:
Thread thread = new Thread (new Runnable () @Override public void run () System.out.println ("My runnable");); Thread.start ();
Sostituire questa classe anonima con un'espressione lambda può rendere questo compito eseguito frequentemente tanto più conciso:
Runnable r = () -> System.out.println ("My runnable"); ; // Avvia il nuovo thread // new Thread (r) .start ();
Infine, se stai usando la libreria RxJava o RxAndroid, puoi usare le espressioni lambda per aiutarti a creare osservabili.
Qui, stiamo creando un semplice Osservabile
che emette la stringa Hello Worlda tutti i suoi Gli osservatori
:
Observable.just ("Hello, world!") .Subscribe (new Action1() @ Override public void call (String s) Log.d (TAG, s); );
L'uso di un'espressione lambda ti consente di sostituire tutto ciò Action1
codice con una sola riga:
Observable.just ("Hello, world!") .Subscribe (s -> Log.d (TAG, s));
Dopo aver letto tutta la teoria alla base di una nuova funzionalità, la prossima sfida sta prendendo l'abitudine di effettivamente utilizzando questa nuova funzionalità. Questo può essere particolarmente difficile con qualcosa come lambda, che sono progettati per essere utilizzati al posto di codice boilerplate familiare, in quanto c'è sempre la tentazione di ricorrere semplicemente a ciò che si sa.
Android Studio ha alcune funzionalità che possono aiutarti a darti quella spinta finale per sostituire il codice familiare-ma-clunky con le nuove espressioni lambda brillanti.
La prima caratteristica è il menu delle azioni intent di Android Studio, che può convertire automaticamente qualsiasi classe anonima compatibile nell'espressione lambda equivalente. Questo è perfetto se non sei mai sicuro di come scrivere un particolare pezzo di codice in un formato lambda: semplicemente scrivilo come al solito, e poi usa la funzione di auto-conversione del menu di azione intent.
Per convertire automaticamente una classe anonima in un'espressione lambda:
In alternativa, puoi utilizzare lo strumento di ispezione di Android Studio per contrassegnare ogni classe anonima che potresti potenzialmente sostituire con un'espressione lambda, su tutto il tuo progetto. Puoi quindi riscrivere manualmente ogni classe anonima o lasciare che la funzione di auto-conversione di Android Studio mostri come è stata eseguita.
Per evidenziare ogni classe anonima che Android Studio potrebbe potenzialmente sostituire con un'espressione lambda:
Il riquadro Risultati ispezione dovrebbe ora apparire e visualizzare un elenco di tutte le classi anonime che è possibile sostituire con un'espressione lambda. Per dare un'occhiata più da vicino a una classe anonima, semplicemente doppio click quella classe nel Risultati di ispezione finestra, e Android Studio aprirà il file e ti porterà alla riga esatta che contiene questa particolare classe anonima.
Per sostituire la classe anonima attualmente selezionata con un'espressione lambda, dai il Sostituire con lambda pulsante un clic.
Se Android Studio non apre automaticamente la finestra Risultati ispezione, puoi avviarla manualmente selezionando Visualizza> Finestre degli strumenti> Risultati dell'ispezione dalla barra degli strumenti di Android Studio. Se i risultati dell'ispezione non lo fa apparire nel Tool Windows sottomenu, quindi potrebbe essere necessario selezionare Analizza> Controlla codice ... prima dalla barra degli strumenti di Android Studio.
Nonostante i numerosi vantaggi che le espressioni lambda hanno da offrire, c'è uno svantaggio principale di cui dovresti essere a conoscenza prima di aggiungerli al tuo codice. Dato che lambda non ha un nome, non puoi chiamarli direttamente dal tuo codice di test, quindi aggiungere un numero elevato di lambda al tuo progetto può rendere più difficile il test.
Idealmente, le espressioni lambda dovrebbero essere troppo semplici da interrompere, quindi non essere in grado di testare le unità non dovrebbe essere un problema troppo grande. Tuttavia, se hai bisogno di testare un lambda, puoi sempre trattarlo come metodo privato e testare l'unità risultato, piuttosto che il lambda stesso. In alternativa, è possibile ridefinire l'espressione lambda nel proprio metodo, in modo da poter fare riferimento direttamente e quindi testarlo normalmente.
In questo primo post sulle funzionalità del linguaggio Java 8, abbiamo esaminato come impostare i progetti Android per supportare Java 8 e come ridurre il codice boilerplate sostituendo le classi anonime con espressioni lambda.
Nel prossimo post, ti mostrerò come tagliare ancora più codice dai tuoi progetti Android combinando espressioni lambda con riferimenti al metodo e come puoi migliorare le interfacce con i metodi di interfaccia statici e predefiniti.
Nel frattempo, dai uno sguardo ad alcuni dei nostri altri post sullo sviluppo di app per Android!