In questa serie in tre parti, abbiamo dato un'occhiata approfondita a Kotlin, un linguaggio di programmazione moderno per le app Android che viene eseguito nella Java Virtual Machine (JVM).
Sebbene Kotlin sia lontano dall'unico linguaggio di programmazione alternativo progettato per funzionare sulla JVM, ha molto da offrire agli sviluppatori Android. Quindi, se di recente ti sei sentito frustrato con la parte Java dello sviluppo di Android, allora ti consigliamo di provare a dare Kotlin.
Nelle prime due puntate abbiamo trattato quanto segue:
Java vs. Kotlin: dovresti utilizzare Kotlin per lo sviluppo Android? In questo articolo introduttivo, abbiamo esaminato ciò che Kotlin ha da offrire agli sviluppatori Android, nonché alcuni potenziali svantaggi di cui devi essere a conoscenza prima di decidere se Kotlin è giusto per te.
Codifica delle app Android funzionali in Kotlin: come iniziare. In questo post, abbiamo visto come configurare Android Studio per supportare il codice Kotlin, creato un'app per Android scritta interamente in Kotlin, familiarizzato con la sintassi di base di Kotlin e persino visto come passare a Kotlin può significare che non devi mai scrivere un altro findViewById
ancora.
Ora che sei in una posizione in cui puoi sostituire le porzioni Java dei tuoi progetti con il codice Kotlin che ha lo stesso risultato finale, passiamo ad osservare alcune aree in cui Kotlin ha il vantaggio su Java.
In questa puntata finale, esploreremo alcune delle funzionalità di Kotlin più avanzate che ti consentono di eseguire attività che potrebbero essere molto più dettagliate in Java o non raggiungibili con Java da solo.
Alla fine di questo articolo, saprai come usare Kotlin per tagliare una tonnellata di codice boilerplate dai tuoi progetti, estendere le classi esistenti con nuove funzionalità e rendere quelle frustranti NullPointerException
è una cosa del passato.
Quante volte vi siete imbattuti in un? NullPointerException
mentre collaudi il tuo codice? Oggi è abbastanza chiaro che consentire agli sviluppatori di assegnare null a un riferimento a un oggetto non è stato il migliore scelta di design! Il tentativo di utilizzare un riferimento a un oggetto con valore null è un'enorme fonte di errori in molti linguaggi di programmazione, incluso Java. Infatti, NullPointerException
è stata una così grande fonte di fastidio che Java 8 ha aggiunto il @NonNull
annotazione specifica per provare e correggere questo difetto nel suo sistema di tipi.
Il problema sta nel fatto che Java ti permette di impostare qualsiasi variabile di un tipo di riferimento su null, ma se in qualsiasi momento provi a usare un riferimento che punta a null, la variabile non saprà dove cercare perché l'oggetto in realtà non esiste. A questo punto, la JVM non può continuare il normale percorso di esecuzione: l'applicazione si arresta in modo anomalo e si incontrano a NullPointerException
. Provare a chiamare un metodo su un riferimento nullo o tentare di accedere a un campo di un riferimento nullo attiveranno entrambi a NullPointerException
.
Se hai provato il dolore di NullPointerException
s (e non abbiamo noi tutti ad un certo punto?) poi ci sono buone notizie: la sicurezza nulla è integrata nel linguaggio Kotlin. Il compilatore Kotlin non ti consente di assegnare un valore nullo a un riferimento a un oggetto, poiché controlla specificamente il tuo codice per la presenza di possibili oggetti nulli durante la compilazione. Se il compilatore Kotlin rileva che a NullPointerException
può essere lanciato in fase di runtime, quindi il tuo codice fallirà in fase di compilazione.
Il design a prova di nulla di Kotlin significa che non incontrerai (quasi) situazioni nulle e NullPointerException
s originato dal codice Kotlin. L'unica eccezione è se inneschi un NullPointerException
usando in modo errato uno degli operatori speciali di Kotlin o se si utilizza uno di questi operatori per attivare deliberatamente un NullPointerException
(esploreremo gli operatori più in dettaglio più avanti in questo articolo).
In Kotlin, tutte le variabili sono considerate non annullabili per impostazione predefinita, quindi il tentativo di assegnare un valore nullo a una variabile comporterà un errore di compilazione. Ad esempio, il seguente non verrà compilato:
esempio var: String = null
Se si desidera che una variabile accetti un valore nullo, sarà necessario contrassegnare esplicitamente tale variabile come annullabile. Questo è l'esatto opposto di Java, dove ogni oggetto è considerato nullable per impostazione predefinita, che è una parte enorme del perché NullPointerException
s sono così comuni in Java.
Se si desidera dichiarare esplicitamente che una variabile può accettare un valore nullo, è necessario aggiungere un ?
al tipo di variabile. Ad esempio, il seguente volontà compilare:
esempio var: stringa? = null
Quando il compilatore vede questo tipo di dichiarazione, riconosce che questa è una variabile nullable e la tratterà in modo un po 'diverso, impedendo in particolare di chiamare un metodo o accedere a una proprietà su questo riferimento nullable, ancora una volta aiutandoti a evitare quelle fastidiose NullPointerExceptions . Ad esempio, il seguente non verrà compilato:
esempio var: stringa? = null example.size
Sebbene il design di Kotlin significhi che è difficile incontrare NullPointerExceptions che proviene dal codice Kotlin, se il tuo progetto presenta una combinazione di Kotlin e Java, allora le porzioni Java del tuo progetto possono ancora essere una fonte di NullPointerExceptions.
Se stai lavorando con una combinazione di file Kotlin e Java (o forse hai specificamente bisogno di introdurre valori Null nel tuo codice Kotlin) allora Kotlin include una serie di operazioni speciali che sono progettate per aiutarti a gestire con garbo qualsiasi valore nullo che incontri.
L'operatore di chiamata sicura ?.
ti fornisce un modo per gestire riferimenti che potrebbero potenzialmente contenere un valore nullo, assicurando al contempo che qualsiasi chiamata a questo riferimento non risulti in a NullPointerException
.
Quando si aggiunge un operatore di Chiamata sicura a un riferimento, tale riferimento verrà verificato per un valore nullo. Se il valore è nullo, viene restituito il valore null, altrimenti il riferimento all'oggetto verrà utilizzato come previsto in origine. Mentre potresti ottenere lo stesso effetto usando un Se
dichiarazione, l'operatore di chiamata sicura consente di eseguire lo stesso lavoro in molto meno codice.
Ad esempio, verrà restituito il seguente a.size
solo se un
non è null-altrimenti, restituirà null:
un? .size
Puoi anche concatenare gli operatori di chiamate sicure insieme:
val number = person? .address? .street? .number
Se una qualsiasi delle espressioni di questa serie è nullo, il risultato sarà nullo, altrimenti il risultato sarà il valore richiesto.
A volte avrai un'espressione che potrebbe potenzialmente contenere un valore nullo, ma non vuoi lanciare a NullPointerException
anche se questo valore fa diventare nullo.
In queste situazioni, puoi utilizzare l'operatore Elvis di Kotlin ?:
per fornire un valore alternativo che verrà utilizzato ogni volta che il valore risulta nullo, che è anche un buon modo per impedire la propagazione di valori nulli nel codice.
Diamo un'occhiata ad un esempio dell'operatore Elvis in azione:
fun setName (name: String?) username = name?: "N / A"
Qui, se il valore a sinistra dell'operatore Elvis è non null allora viene restituito il valore del lato sinistro (nome
). Ma se il valore a sinistra dell'operatore Elvis è null allora verrà restituita l'espressione a destra, che in questo caso è N / A
.
Se vuoi forzare il tuo codice Kotlin a lanciare un NullPointerException in stile Java, puoi usare il !!
operatore. Per esempio:
val number = firstName !!. length
Qui, stiamo usando il !!
operatore per affermare che il nome di battesimo
la variabile non è nulla. Fintanto che nome di battesimo
contiene un riferimento valido, quindi il numero variabile è impostato su lunghezza
della stringa. Se nome di battesimo
non contiene un riferimento valido, quindi Kotlin lancerà a NullPointerException
.
Un'espressione lambda rappresenta una funzione anonima. Lambdas è un ottimo modo per ridurre la quantità di codice necessaria per eseguire alcune attività che si verificano continuamente nello sviluppo Android, ad esempio, la scrittura di listener e callback.
Java 8 ha introdotto espressioni lambda native e ora sono supportate in Android Nougat. Sebbene questa caratteristica non sia qualcosa di unico per Kotlin, vale comunque la pena dargli un'occhiata. Inoltre, se stai lavorando su un progetto che contiene sia codice Kotlin che Java, ora puoi usare espressioni lambda su tutto il tuo progetto!
Un'espressione lambda comprende un set di parametri, un operatore lambda (->
) e un corpo di una funzione, disposti nel seguente formato:
x: Int, y: Int -> x + y
Quando costruisci espressioni lambda in Kotlin, devi tenere presente le seguenti regole:
L'espressione lambda dovrebbe essere circondata da parentesi graffe.
Se l'espressione contiene parametri, è necessario dichiararli prima del ->
simbolo della freccia.
Se stai lavorando con più parametri, dovresti separarli con virgole.
Il corpo segue il ->
cartello.
Il vantaggio principale delle espressioni lambda è che consentono di definire funzioni anonime e quindi di passare immediatamente a queste funzioni come espressione. Ciò consente di eseguire molte attività di sviluppo comuni in modo più succinto rispetto a Java 7 e versioni precedenti, poiché non è più necessario scrivere le specifiche della funzione in una classe o un'interfaccia astratta. In effetti, la mancanza di lambda in Java 7 e precedenti è una grande parte del motivo per cui gli ascoltatori e i callback sono sempre stati così clunky in Android.
Diamo un'occhiata a un esempio comune: aggiungere un listener di clic a un pulsante. In Java 7 e precedenti, questo in genere richiede il seguente codice:
button.setOnClickListener (new View.OnClickListener () @Override public void onClick (View v) Toast.makeText (this, "Button cliccato", Toast.LENGTH_LONG) .show (););
Tuttavia, le funzioni lambda di Kotlin consentono di impostare un listener di clic utilizzando una singola riga di codice:
button.setOnClickListener (view -> toast ("Pulsante cliccato"))
Già, questo è molto più succinto e più facile da leggere, ma possiamo andare oltre: se una funzione assume un'altra funzione come ultimo parametro, puoi passarla al di fuori dell'elenco delle parentesi:
button.setOnClickListener () toast ("Pulsante cliccato")
E se la funzione ha solo un parametro che è una funzione, puoi rimuovere completamente le parentesi:
button.setOnClickListener toast ("Pulsante cliccato")
Simile a C #, Kotlin consente di aggiungere nuove funzionalità a classi esistenti che altrimenti non sarebbe possibile modificare. Quindi se pensi che a una classe manchi un metodo utile, allora perché non aggiungerlo tu stesso, tramite una funzione di estensione?
Crei una funzione di estensione anteponendo il nome della classe che desideri estendere al nome della funzione che stai creando.
Per esempio:
fun AppCompatActivity.toast (msg: String) Toast.makeText (this, msg, Toast.LENGTH_LONG) .show ()
Si noti che il Questo
parola chiave all'interno della funzione di estensione corrisponde al AppCompatActivity
esempio che .crostini
è chiamato.
In questo esempio, devi solo importare il AppComptActivity
e Crostini
classi nel tuo .kt file e quindi sei pronto per chiamare il .
notazione su istanze della classe estesa.
Quando si tratta di sviluppo Android, è possibile trovare funzioni di estensione particolarmente utili per dare ViewGroups
la capacità di gonfiarsi, ad esempio:
divertente ViewGroup.inflate (@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): Visualizza return LayoutInflater .from (context) .inflate (layoutRes, this, attachToRoot)
Quindi, invece di dover scrivere quanto segue:
val view = LayoutInflater .from (parent) .inflate (R.layout.activity_main, parent, false)
Puoi semplicemente usare la tua funzione di estensione:
val view = parent.inflate (R.layout.activity_main)
In Java, la creazione di singleton è stata in genere piuttosto prolissa, richiedendo di creare una classe con un costruttore privato e quindi creare tale istanza come attributo privato.
Il risultato finale è solitamente qualcosa del genere:
public class Singleton private static Singleton singleton = new Singleton (); private Singleton () public static Singleton getInstance () return singleton;
Piuttosto che dichiarare una classe, Kotlin ti permette di definire un singolo oggetto, che è semanticamente uguale a un singleton, in una riga di codice:
oggetto KotlinSingleton
È quindi possibile utilizzare questo singleton subito, ad esempio:
oggetto KotlinSingleton fun myFunction () [...] KotlinSingleton.myFunction ()
In questo articolo, abbiamo analizzato a fondo il design a prova di errore di Kotlin e abbiamo visto come puoi garantire che i tuoi progetti Android rimangano nulli anche quando contengono una combinazione di codice Java e Kotlin utilizzando una gamma di operatori speciali. Abbiamo anche esaminato come è possibile utilizzare le espressioni lambda per semplificare alcune attività di sviluppo comuni in Android e come aggiungere nuove funzionalità alle classi esistenti.
In combinazione con quanto appreso nella Parte 1: Java vs Kotlin e Parte 2: Per iniziare, ora hai tutto il necessario per iniziare a creare app Android efficaci utilizzando il linguaggio di programmazione Kotlin.
Divertiti con il linguaggio Kotlin e, perché no, dai un'occhiata ad altri nostri corsi e tutorial sulla programmazione Android?