Come ottenere solo parte di un array in Java
Fonte:
Asyncq La copia di parte di un array è un'operazione molto comune che ogni sviluppatore incontra. In questo articolo vedremo il codice in stile imperativo tradizionale e in stile dichiarativo moderno con espressione lambda e API di streaming.
Approccio imperativo
Lo stile di programmazione imperativo è comune da tempo in Java. Pertanto, è naturale che gli sviluppatori Java scrivano il codice seguente per copiare una parte specifica dell'array originale. Per fare ciò, è sufficiente scorrere gli elementi, filtrando solo quelli necessari e scriverli nell'array finale.
private static int[] copyArray(){
int[] numbers = {1,2,3,4,5,6,7};
int[] subArray = new int[numbers.length-3];
int j =3;
for (int i=0;i<subArray.length;i++){
subArray[i] = numbers[j+i];
}
System.out.println(Arrays.toString(subArray));
return subArray;
}
Molti di noi spesso dimenticano che la libreria Java
Arrays ha un comodo metodo
copyOfRange . Questo metodo può essere utilizzato per copiare parte di un array passando da e verso l'indice.
private static int[] copyArray1(){
int[] numbers = {1,2,3,4,5,6,7};
int[] subArray = Arrays.copyOfRange(numbers,3,numbers.length);
System.out.println(Arrays.toString(subArray));
return subArray;
}
Approccio dichiarativo
A partire da Java 8 possiamo utilizzare l'API Streams per copiare parte di un array. Nel codice seguente possiamo passare
int[] e filtrare solo i valori maggiori di 3 e infine copiarli in un array.
private static void copyArray2(){
int[] numbers = {1,2,3,4,5,6,7};
int[] subArray = Arrays.stream(numbers).filter(a-> a>3).toArray();
System.out.println(Arrays.toString(subArray));
}
Il codice sopra è una copia basata sul valore di una porzione dell'array, ma possiamo anche copiare in base a un indice. Sotto il codice trasmettiamo
Intstream da i=0; i=len(array) . Tipicamente nel codice imperativo scriviamo un ciclo
for dall'indice iniziale all'indice finale e iteriamo su ciascun elemento. Possiamo fare la stessa cosa usando Intstream e accedere all'elemento
indice .
int[] subArray1 = IntStream
.range(0, numbers.length)
.filter(i -> i > 3)
.map(a->numbers[a]).toArray();
System.out.println(Arrays.toString(subArray1));
Anche se il metodo sopra funziona, abbiamo un altro modo in cui possiamo usare
AtomicInteger per copiare parte dell'array. Ha un metodo
getAndIncrement che essenzialmente fornisce un indice e lo incrementa di 1.
AtomicInteger atomicInteger = new AtomicInteger();
int[] subArray2 = Arrays.stream(numbers).filter(i -> atomicInteger.getAndIncrement() > 3).toArray();
System.out.println(Arrays.toString(subArray2));
Conclusione
In questo articolo abbiamo discusso come copiare parte di un array Java utilizzando gli stili imperativo e dichiarativo. Preferirei lavorare in uno stile dichiarativo poiché rende il mio codice più leggibile e meno dettagliato.
Interfacce e classi astratte in Java
Fonte:
Devgenius Quando impariamo il linguaggio Java, ci imbattiamo sicuramente in un concetto chiamato Interfacce. Le interfacce sono una delle caratteristiche chiave di Java, quindi ogni sviluppatore dovrebbe sapere come usarle. È importante ricordare che le interfacce presentano sia vantaggi che svantaggi. Andiamo più a fondo nella comprensione delle interfacce. Quando implementiamo le interfacce, incontriamo classi astratte. Cosa sono le classi astratte? A cosa servono? Cos'è un'interfaccia? Come vengono utilizzati? Perché le interfacce utilizzano classi astratte? Riceverai le risposte a tutte queste domande in questo articolo.
Cos'è un'interfaccia?
Un'interfaccia è un meccanismo speciale in Java che descrive il comportamento e aiuta a raggiungere l'astrazione. È simile a una classe in molti modi perché ha costanti statiche e metodi astratti. Le interfacce possono avere solo metodi astratti (metodi senza corpo).
Breve differenza tra interfaccia e classe astratta:
- L'interfaccia non ha metodi implementati; sono tutti pubblici e non ci sono variabili di classe.
- Una classe astratta è una classe che non ha uno o più metodi implementati.
A partire da Java 9, possiamo anche utilizzare metodi
private ,
default e
static nelle interfacce . Passiamo ora alla semplice logica dell'interfaccia utilizzata per ottenere l'astrazione.
Cos'è l'astrazione?
Facciamo un esempio di vita reale. Tutti usiamo app sui nostri telefoni cellulari. Ogni volta che vogliamo utilizzare un'applicazione, dobbiamo creare un account al suo interno. Quando ci registriamo tramite il nostro numero di telefono, una password monouso viene inviata al nostro telefono cellulare. Sappiamo che la password viene ricevuta dopo aver fatto clic sul pulsante "Ottieni password" nell'applicazione, ma non sappiamo come funziona questo sistema nel backend e cosa succede effettivamente dopo aver fatto clic sul pulsante. Ora, il processo di completamento con successo delle attività senza mostrare all'utente cosa sta realmente accadendo nel backend è noto come astrazione. In Java, possiamo ottenere l'astrazione utilizzando interfacce e classi astratte.
Perché utilizzare l'interfaccia?
Ci sono tre motivi per utilizzare l'interfaccia:
- Per raggiungere l'astrazione.
- Per supportare la funzionalità di ereditarietà multipla.
- Per ottenere un accoppiamento allentato.
Come utilizzare l'interfaccia?
Un'interfaccia viene dichiarata utilizzando
la parola chiave Interface . Fornisce l'astrazione, ovvero dichiara la struttura della classe. Tutti i metodi in un'interfaccia sono astratti e sono impostati su public, static e final per impostazione predefinita (
public ,
static ,
final ). Qualunque classe implementi un'interfaccia deve implementare tutti i metodi dichiarati nell'interfaccia.
interface <interface_name>{
}
Similmente all'astrazione dell'interfaccia, l'astrazione può essere ottenuta anche utilizzando classi astratte.
Cosa sono le classi astratte?
Le classi astratte sono classi precedute dalla parola chiave
abstract . Contengono sia metodi astratti che concreti (con un corpo). Le classi astratte non possono essere istanziate, devono essere estese e i loro metodi devono essere implementati. Una classe astratta descrive alcuni oggetti astratti (auto, persona, ecc.), non solo il comportamento. Ricordare:
- Una classe astratta deve essere dichiarata con la parola chiave abstract .
- Possono esserci metodi astratti e non astratti.
- Non è possibile creare un'istanza di una classe astratta.
- Può avere costruttori e metodi statici.
- Può avere metodi finali che forzeranno la sottoclasse a non modificare il corpo del metodo.
Esempio di una classe astratta con un metodo astratto: In questo esempio ,
Bike è una classe astratta che contiene solo un metodo astratto eseguito. La sua implementazione è prevista dalla classe
Honda .
abstract class Bike{
abstract void run();
}
class Honda4 extends Bike{
void run(){System.out.println("running safely");}
public static void main(String args[]){
Bike obj = new Honda4();
obj.run();
}
}
Classe astratta avente un costruttore, un membro dati e metodi: una classe astratta può avere un membro dati, un metodo astratto, un corpo del metodo (metodo non astratto), un costruttore e persino un metodo
main() .
abstract class Bike{
Bike(){System.out.println("bike is created");}
abstract void run();
void changeGear(){System.out.println("gear changed");}
}
class Honda extends Bike{
void run(){System.out.println("running safely..");}
}
class TestAbstraction2{
public static void main(String args[]){
Bike obj = new Honda();
obj.run();
obj.changeGear();
}
}
Ora sorge la domanda principale. Se le interfacce e le classi astratte aiutano con l'astrazione, quale è meglio usare? La risposta è che Java non supporta l'ereditarietà multipla come fa C++. Cioè, se dobbiamo ottenere l'ereditarietà multipla, allora dovremmo usare le interfacce. In altre parole, le classi astratte aiutano dall'1 al 100% dei casi e le interfacce aiutano nel 100% dei casi. Se abbiamo bisogno di un comportamento, dobbiamo usare un'interfaccia. Se parliamo di un oggetto concettuale, dobbiamo utilizzare una classe astratta.
Esempio di interfaccia Java
In questo esempio, l' interfaccia
Drawable ha un solo metodo. La sua implementazione è fornita dalle classi
Rectangle e
Circle . In uno scenario reale, l'interfaccia è definita da qualcun altro e la sua implementazione è fornita da diversi fornitori di implementazione. Inoltre, viene utilizzato da qualcun altro. Parte dell'implementazione è nascosta dall'utente utilizzando l'interfaccia.
interface Drawable{
void draw();
}
class Rectangle implements Drawable{
public void draw(){System.out.println("drawing rectangle");}
}
class Circle implements Drawable{
public void draw(){System.out.println("drawing circle");}
}
class TestInterface1{
public static void main(String args[]){
Drawable d=new Circle();
d.draw();
}}
Eredità multipla in Java utilizzando l'interfaccia
Se una classe implementa più interfacce o un'interfaccia estende più interfacce, si parla di ereditarietà multipla.
interface Printable{
void print();
}
interface Showable{
void show();
}
class A7 implements Printable,Showable{
public void print(){System.out.println("Hello");}
public void show(){System.out.println("Welcome");}
public static void main(String args[]){
A7 obj = new A7();
obj.print();
obj.show();
}
}
Domanda: L'ereditarietà multipla non è supportata tramite una classe in Java, ma è possibile tramite un'interfaccia, perché? Come già spiegato nella sezione sull'ereditarietà, l'ereditarietà multipla non è supportata nell'esempio della classe a causa dell'ambiguità. Tuttavia, è supportato dall'esempio dell'interfaccia perché non contiene ambiguità. Il motivo è che la sua implementazione è fornita dalla classe di implementazione.
GO TO FULL VERSION