Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Java 8

Java 8 per lo sviluppo di Android: metodi predefiniti e statici

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Java 8 for Android Development.
Java 8 for Android: Cleaner Code With Lambda Expressions
Java 8 for Android Development: Stream API and Date & Time Libraries

Italian (Italiano) translation by Loris Pizii (you can also view the original English article)

Java 8 è stato un enorme passo avanti per il linguaggio di programmazione e ora, con il rilascio di Android Studio 3.0, gli sviluppatori Android hanno finalmente accesso a un supporto integrato per alcune delle funzioni più importanti di Java 8.

In questa serie di tre parti, abbiamo esplorato le funzionalità di Java 8 che puoi iniziare a utilizzare nei tuoi progetti Android oggi.In codice più pulito con le espressioni Lambda, abbiamo impostato il nostro sviluppo per utilizzare il supporto Java 8 fornito dal toolchain di default di Android, prima di approfondire le espressioni di lambda.

In questo post esamineremo due modi diversi per dichiarare metodi non-astratti nelle vostre interfacce (qualcosa che non era possibile nelle versioni precedenti di Java).Risponderemo anche alla domanda, ora che le interfacce possono implementare metodi, qual è la differenza tra le classi astratte e le interfacce?

Copriamo anche una funzionalità Java 8 che ti dà la libertà di utilizzare la stessa annotazione più volte che desideri nella stessa posizione, pur restando indietro compatibile con le versioni precedenti di Android.

Ma prima di tutto, esaminiamo una funzionalità Java 8 che è stata progettata per essere utilizzata in combinazione con le espressioni lambda che abbiamo visto nel post precedente.

Scrivere le espressioni Lambda Cleaner, con i riferimenti di metodo

Nell'ultimo messaggio, hai visto come puoi usare le espressioni lambda per rimuovere un sacco di codice di avvio dalle applicazioni Android. Tuttavia, quando un'espressione lambda sta semplicemente chiamando un singolo metodo che ha già un nome, è possibile tagliare ancora di più il codice dal progetto utilizzando un riferimento di metodo.

Ad esempio, questa espressione lambda è veramente reindirizzando il lavoro ad un metodo handleViewClick esistente:

In questo scenario, possiamo fare riferimento a questo metodo per nome, utilizzando l'operatore di riferimento del metodo ::. Si crea questo tipo di riferimento di metodo, utilizzando il seguente formato:

Nel nostro esempio del pulsante di azione galleggiante, possiamo utilizzare un riferimento metodico come corpo dell'espressione lambda:

Si noti che il metodo a cui si fa riferimento deve avere gli stessi parametri dell'interfaccia - in questa istanza, ovvero Visualizza.

È possibile utilizzare l'operatore di riferimento del metodo (: :) per fare riferimento a una delle seguenti opzioni:

Un metodo statico

Se si dispone di un'espressione lambda che chiama un metodo statico:

Poi puoi trasformarlo in un riferimento di metodo:

Ad esempio, se aveste un metodo statico PrintMessage in una classe MyClass, il tuo metodo di riferimento potrebbe essere simile a questo:

Metodo di istanza di un oggetto specifico

Questo è un metodo di istanza di un oggetto che è conosciuto in anticipo, consentendo di sostituire:

Con:

Quindi, se hai avuto la seguente espressione lambda:

Quindi introduzione di un metodo di riferimento vi darà quanto segue:

Un metodo di istanza di un oggetto arbitrario di un particolare tipo

Questo è un metodo di istanza di un oggetto arbitrario che verrà fornito in seguito e scritto nel seguente formato:

Riferimenti del costruttore

I riferimenti del costruttore sono simili ai riferimenti di metodo, ad eccezione che si utilizza la nuova parola chiave per invocare il costruttore. Ad esempio, Button::new è un riferimento costruttore per il Button di classe, anche se il costruttore esatto richiamato dipende dal contesto.

Utilizzando i riferimenti del costruttore, è possibile attivare:

In:

Ad esempio, se si avesse la seguente interfaccia MyInterface:

Quindi è possibile utilizzare riferimenti costruttori per creare nuove istanze Studente:

È inoltre possibile creare riferimenti di costruttori per i tipi di array. Ad esempio, un riferimento costruttore per un array di int è int []::new.

Aggiungi metodi predefiniti alle interfacce

Prima di Java 8, è possibile includere solo metodi astratti nelle interfacce (ovvero metodi senza un corpo) che hanno reso difficile l'evoluzione delle interfacce, post-pubblicazione.

Ogni volta che hai aggiunto un metodo a una definizione di interfaccia, qualsiasi classe che ha implementato questa interfaccia improvvisamente manca un'implementazione. Ad esempio, se si dispone di un'interfaccia (MyInterface) utilizzata da MyClass, aggiungere un metodo a MyInterface interromperà la compatibilità con MyClass.

Nel migliore dei casi dove siete stati responsabili del piccolo numero di classi che utilizzavano MyInterface, questo comportamento sarebbe fastidioso ma gestibile: dovrai solo mettere da parte un po 'di tempo per aggiornare le tue classi con la nuova implementazione. Tuttavia, le cose potrebbero diventare molto più complicate se un gran numero di classi implementa MyInterface o se l'interfaccia è stata utilizzata in classi per cui non sei responsabile.

Mentre ci sono stati diversi soluzioni per questo problema, nessuno di loro era ideale. Ad esempio, è possibile includere nuovi metodi in una classe astratta, ma ciò richiederebbe comunque a tutti di aggiornare il proprio codice per estendere questa classe astratta; e, mentre potresti estendere l'interfaccia originale con una nuova interfaccia, chiunque volesse utilizzare questi nuovi metodi avrebbe bisogno di riscrivere tutti i riferimenti di interfaccia esistenti.

Con l'introduzione di metodi predefiniti in Java 8, è ora possibile dichiarare metodi non-astratti (cioè metodi con un corpo) all'interno delle interfacce, in modo da poter finalmente creare implementazioni predefinite per i metodi.

Quando si aggiunge un metodo all'interfaccia come metodo predefinito, qualsiasi classe che implementa questa interfaccia non necessariamente necessita di fornire una propria implementazione, che consente di aggiornare le interfacce senza interrompere la compatibilità. Se si aggiunge un metodo nuovo a un'interfaccia come metodo predefinito, ogni classe che utilizza questa interfaccia ma non fornisce la propria implementazione erediterà semplicemente l'implementazione predefinita del metodo. Poiché la classe non manca di un'implementazione, continuerà a funzionare come normale.

Infatti, l'introduzione di metodi predefiniti è stata la ragione per cui Oracle ha potuto apportare un numero così elevato di aggiunte all'API Collection in Java 8.

La raccolta è un'interfaccia generica utilizzata in molte classi diverse, quindi l'aggiunta di nuovi metodi a questa interfaccia ha potuto interrompere innumerevoli righe di codice. Invece di aggiungere nuovi metodi all'interfaccia di raccolta e di rompere ogni classe derivata da questa interfaccia, Oracle ha creato la funzionalità di metodo predefinito, quindi aggiunge questi nuovi metodi come metodi predefiniti. Se si esamina il nuovo metodo Collection.Stream () (che esploreremo in dettaglio nella parte tre), vedrai che è stato aggiunto come metodo predefinito:

La creazione di un metodo predefinito è semplice: basta aggiungere il modificatore predefinito alla tua firma del metodo:

Ora, se MyClass utilizza MyInterface ma non fornisce la propria implementazione di defaultMethod, erediterà l'implementazione predefinita fornita da MyInterface. Ad esempio, la classe seguente si compila ancora:

Una classe di implementazione può ignorare l'implementazione predefinita fornita dall'interfaccia, in modo che le classi continuino a controllare pienamente le loro implementazioni.

Mentre i metodi predefiniti sono un'aggiunta benvenuta per i progettisti API, possono occasionalmente causare un problema per gli sviluppatori che tentano di utilizzare più interfacce nella stessa classe.

Immagina che, oltre a MyInterface, hai i seguenti:

Sia MyInterface che SecondInterface contengono un metodo predefinito con la stessa firma (defaultMethod). Ora immaginate di provare a utilizzare entrambe queste interfacce nella stessa classe:

A questo punto si dispongono di due implementazioni in conflitto di defaultMethod e il compilatore non ha idea di quale metodo deve utilizzare, per cui si incontra un errore di compilatore.

Un modo per risolvere questo problema è quello di ignorare il metodo in conflitto con la propria implementazione:

L'altra soluzione è specificare quale versione di defaultMethod da implementare, utilizzando il seguente formato:

Quindi, se voleste chiamare l'implementazione MyInterface#defaultMethod (), allora utilizzeresti quanto segue:

Utilizzo di metodi statici nelle interfacce di Java 8

Simile ai metodi predefiniti, i metodi di interfaccia statica forniscono un modo per definire i metodi all'interno di un'interfaccia. Tuttavia, a differenza dei metodi predefiniti, una classe di implementazione non può ignorare i metodi statici di un'interfaccia.

Se si dispone di metodi statici specifici per un'interfaccia, i metodi di interfaccia statica di Java 8 consentono di mettere questi metodi all'interno dell'interfaccia corrispondente, invece di memorizzarli in una classe separata.

Si crea un metodo statico inserendo la parola chiave statica all'inizio della firma del metodo, ad esempio:

Quando si implementa un'interfaccia che contiene un metodo di interfaccia statica, quel metodo statico è ancora parte dell'interfaccia e non viene ereditato dalla classe che lo implementa, pertanto è necessario prefisso del metodo con il nome dell'interfaccia, ad esempio:

Ciò significa anche che una classe e un'interfaccia possono avere un metodo statico con la stessa firma. Ad esempio, utilizzando MyClass.staticMethod e MyInterface.staticMethod nella stessa classe non causerà un errore di compilazione.

Quindi, sono interfacce essenzialmente solo classi astratte?

L'aggiunta di metodi di interfaccia statica e di metodi predefiniti ha indotto alcuni sviluppatori a stabilire se le interfacce Java stanno diventando più simili a classi astratte. Tuttavia, anche con l'aggiunta di metodi di interfaccia statica e di default, esistono ancora alcune differenze tra le interfacce e le classi astratte:

  • Le classi astratte possono avere variabili definitive, non finali, statiche e non statiche, mentre un'interfaccia può avere solo variabili statiche e definitive.
  • Le classi astratte consentono di dichiarare campi che non sono statici e finali, mentre i campi di un'interfaccia sono intrinsecamente statici e finali.
  • Nelle interfacce, tutti i metodi dichiarati o definiti come metodi predefiniti sono intrinsecamente pubblici, mentre nelle classi astratte è possibile definire metodi concreti pubblici, protetti e privati.
  • Le classi astratte sono classi e quindi possono avere lo stato; le interfacce non possono avere stato associato a loro.
  • È possibile definire costruttori all'interno di una classe astratta, cosa che non è possibile all'interno di interfacce Java.
  • Java consente solo di estendere una classe (indipendentemente dal fatto che sia astratto), ma è possibile implementare tante interfacce come è necessario. Ciò significa che le interfacce hanno tipicamente il bordo quando si richiede un'eredità multipla, anche se devi guardare il diamante mortale della morte!

Applicare la stessa annotazione come molti tempi come vuoi

Tradizionalmente, una delle limitazioni delle annotazioni Java è stata che non puoi applicare la stessa annotazione più di una volta nella stessa posizione. Provare a utilizzare la stessa annotazione più volte e troverai un errore di compilazione.

Tuttavia, con l'introduzione di annotazioni ripetute di Java 8, è ora libero di utilizzare la stessa annotazione più volte che si desidera nella stessa posizione.

Per garantire che il codice rimanga compatibile con le versioni precedenti di Java, è necessario memorizzare le annotazioni ripetute in un'annotazione del contenitore.

Puoi dire al compilatore di generare questo contenitore, completando le seguenti operazioni:

  • Annota l'annotazione in questione con la meta-annotazione @Repeatable (un'annotazione utilizzata per annotare un'annotazione). Ad esempio, se voleste rendere ripetibile l'annotazione @ToDo, utilizzare: @Repeatable(ToDos.class). Il valore tra parentesi è il tipo di annotazione del contenitore che il compilatore genererà.
  • Dichiarare il tipo di annotazione contenente. Questo deve avere un attributo che è una matrice del tipo di annotazione ripetuta, ad esempio:

Tentando di applicare la stessa annotazione più volte senza prima dichiarare che è ripetibile, si verifica un errore al momento della compilazione. Tuttavia, una volta che hai specificato che si tratta di un'annotazione ripetibile, puoi utilizzare questa annotazione più volte in qualsiasi posizione in cui utilizzare un'annotazione standard.

Conclusione

In questa seconda parte della nostra serie su Java 8 abbiamo visto come puoi tagliare ancora più codice di boilerplate dai tuoi progetti Android combinando espressioni di lambda con i riferimenti di metodo e come migliorare le interfacce con i metodi predefiniti e statici.

Nella terza e ultima versione verrà esaminata una nuova API Java 8 che consente di elaborare quantità enormi di dati in modo più efficiente e dichiarativo, senza dover preoccuparsi della concorrenza e della gestione dei thread. Saremo anche legando alcune delle diverse funzioni che abbiamo discusso in questa serie, esplorando il ruolo che le interfacce funzionali devono svolgere in espressioni lambda, metodi di interfaccia statica, metodi predefiniti e altro ancora.

E infine, anche se stiamo ancora aspettando l'API di Data e Ora di Java 8 per arrivare ufficialmente in Android, mostrerò come puoi iniziare a utilizzare questa nuova API nei tuoi progetti Android oggi con l'aiuto di alcuni terzi librerie.

Nel frattempo, guarda alcuni dei nostri altri post sullo sviluppo di applicazioni Java e Android!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.