Struttura Dati Coda in Java
Iniziamo con una Queue. Immagina una fila in un negozio durante una svendita. Ci sono 10 persone; la prima persona è più vicina alle porte del negozio rispetto alle altre, e la decima persona è la più lontana. Quando la prima persona entra nel negozio, esce dalla fila, facendo così avanzare tutta la fila di una posizione. La Queue in Java funziona secondo un principio molto simile.
In questo modo, è possibile implementare diversi programmi in cui la logica della coda è ben strutturata. Ad esempio, implementare una bacheca con piani e attività.
Ma prima, esaminiamo i metodi di base per lavorare con una Queue.
Queue è un'interfaccia da cui eredita la classe LinkedList, che già conosci, quindi utilizzeremo questa implementazione.
In questo modo, si utilizza l'interfaccia come tipo dell'oggetto, ma l'implementazione dell'oggetto sarà LinkedList perché rappresenta una specifica implementazione di questo oggetto. (Ricorda che non è possibile creare oggetti basati su un'interfaccia).
Esempio:
Example.java
1234// `LinkedList` as implementation of the `List` interface: List<T> list = new LinkedList<>(); // `LinkedList` as implementation of the `Queue` interface: Queue<T> queue = new LinkedList<>();
In questo modo, è possibile rendere l'applicazione molto flessibile utilizzando varie implementazioni della stessa interfaccia.
Ma torniamo ai metodi di gestione della Queue.
Metodi
Alcuni dei principali metodi dell'interfaccia Queue sono:
add(element): aggiunge un elemento alla coda, lanciando un'eccezione se l'operazione non è possibile;offer(element): aggiunge un elemento alla coda, restituendotruese ha successo ofalsealtrimenti.
Si può notare che questi metodi svolgono essenzialmente la stessa funzione. Tuttavia, la differenza principale è la sicurezza del metodo offer. In caso di aggiunta non corretta di un elemento, il metodo offer non lancerà un'eccezione e non interromperà l'esecuzione del programma.
Tuttavia, al momento questa caratteristica non è di grande interesse, poiché una normale Queue non ha limiti. Esiste però una struttura chiamata BlockingQueue, che prevede una restrizione sul numero di elementi; in tal caso, questi metodi avranno una differenza significativa.
Vediamo un esempio:
Main.java
1234567891011121314package com.example; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Main { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(2); queue.add("One"); queue.add("Two"); queue.add("Three"); System.out.println("Queue: " + queue); } }
Come puoi vedere, quando si utilizza il metodo add() e si tenta di aggiungere un elemento che non trova spazio nella coda, il programma genera un errore, terminando l'esecuzione in modo imprevisto.
Proviamo la stessa operazione ma con un metodo più sicuro — offer():
Main.java
1234567891011121314package com.example; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Main { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(2); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); System.out.println("Queue: " + queue); } }
Come puoi vedere, ora l'elemento non è stato aggiunto alla coda, ma non è stata nemmeno generata un'eccezione. Quindi, possiamo considerare che l'errore è stato gestito in modo appropriato.
È possibile gestire le eccezioni in modo diverso utilizzando una struttura come try-catch, ma ne parleremo più avanti.
Metodi di Rimozione
remove(): rimuove e restituisce l'elemento dall'inizio della coda, generando un'eccezione se la coda è vuota;poll(): rimuove e restituisce l'elemento dall'inizio della coda, restituendonullse la coda è vuota.
Questi metodi svolgono esattamente la funzione come se la prima persona nella coda entrasse nel negozio e lasciasse la coda. Qui entra in gioco il principio FIFO (First In, First Out). In altre parole, l'elemento che è stato aggiunto per primo alla coda sarà il primo ad essere rimosso.
Qui puoi anche osservare la differenza tra questi due metodi. Il metodo poll() viene utilizzato più spesso rispetto a remove() perché è più sicuro e non genera eccezioni.
Vediamo un esempio:
Main.java
123456789101112131415package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); System.out.println("Queue: " + queue); queue.remove(); queue.remove(); System.out.println("Queue after removal operation: " + queue); } }
Come puoi vedere, il programma genera una NoSuchElementException perché si sta tentando di rimuovere un elemento da una coda vuota.
Per evitare tale eccezione, è preferibile utilizzare il metodo poll():
Main.java
123456789101112131415package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); System.out.println("Queue: " + queue); queue.poll(); queue.poll(); System.out.println("Queue after removal operation: " + queue); } }
Ora, abbiamo rimosso in modo sicuro un elemento dalla coda e nessuna eccezione è stata generata quando si è tentato di rimuovere un elemento da una lista vuota.
La caratteristica di poll() che restituisce null può essere utilizzata, ad esempio, in un ciclo while().
Vediamo un esempio:
Main.java
1234567891011121314151617181920package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (queue.poll() != null) { queue.poll(); } System.out.println("Queue after removal operation: " + queue); } }
In questo modo, è possibile rimuovere tutti gli elementi dalla coda utilizzando un ciclo.
Ricorda che il primo elemento inserito nella coda è quello che viene rimosso! Ad esempio, nel caso dell'esempio sopra, l'elemento con il dato "One" è stato rimosso per primo.
Il principio FIFO è illustrato di seguito:
Main.java
123456789101112131415161718package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); queue.poll(); System.out.println("Queue after removal operation: " + queue); } }
Possiamo passare ai metodi che restituiscono il primo e l'ultimo elemento:
element(): restituisce, ma non rimuove, l'elemento all'inizio della coda, lanciando un'eccezione se la coda è vuota;peek(): restituisce, ma non rimuove, l'elemento all'inizio della coda, restituendonullse la coda è vuota.
L'utilizzo del metodo peek() rappresenta un approccio più affidabile e sicuro, poiché aiuta a evitare potenziali eccezioni.
Vediamo un esempio di utilizzo:
Main.java
12345678910111213141516package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); System.out.println("Queue: " + queue); System.out.println("The first element in the queue: " + queue.peek()); System.out.println("Queue after the `peek()` method: " + queue); } }
È possibile combinare questo metodo con altri metodi della coda.
Se si dispone di una coda con cinque elementi e si ha la necessità di rimuovere tutti gli elementi fino al quarto (incluso), vediamo l'implementazione di tale operazione:
Main.java
123456789101112131415161718192021package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (!queue.peek().equals("Four")) { queue.poll(); } queue.poll(); System.out.println("Queue after removal operation: " + queue); } }
È stato utilizzato un ciclo con una condizione basata sul metodo peek().
È possibile ottimizzare significativamente questo ciclo utilizzando il metodo contains(). Questo metodo restituisce true se l'elemento specificato è presente nella coda e false se non lo è.
Miglioriamo il codice sopra:
Main.java
1234567891011121314151617181920package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (queue.contains("Four")) { queue.poll(); } System.out.println("Queue after removal operation: " + queue); } }
Qui impostiamo una singola condizione per il ciclo while. Siamo riusciti a rimuovere con successo tutti gli elementi fino e compreso l'elemento "Four".
1. Che cos'è una Queue in Java?
2. Quale interfaccia rappresenta una Queue nel Java Collections Framework?
3. Qual è lo scopo del metodo offer() nell'interfaccia Queue?
4. Cosa fa il metodo poll() nell'interfaccia Queue?
5. Quale classe nel package java.util.concurrent di Java rappresenta una coda bloccante con capacità limitata?
6. Cosa succede se si tenta di aggiungere un elemento a una coda piena utilizzando il metodo add()?
Grazie per i tuoi commenti!
Chieda ad AI
Chieda ad AI
Chieda pure quello che desidera o provi una delle domande suggerite per iniziare la nostra conversazione
Can you explain more about the difference between add() and offer() methods?
How does the FIFO principle work in a real-world queue?
What are some practical uses of the Queue interface in Java?
Fantastico!
Completion tasso migliorato a 4
Struttura Dati Coda in Java
Scorri per mostrare il menu
Iniziamo con una Queue. Immagina una fila in un negozio durante una svendita. Ci sono 10 persone; la prima persona è più vicina alle porte del negozio rispetto alle altre, e la decima persona è la più lontana. Quando la prima persona entra nel negozio, esce dalla fila, facendo così avanzare tutta la fila di una posizione. La Queue in Java funziona secondo un principio molto simile.
In questo modo, è possibile implementare diversi programmi in cui la logica della coda è ben strutturata. Ad esempio, implementare una bacheca con piani e attività.
Ma prima, esaminiamo i metodi di base per lavorare con una Queue.
Queue è un'interfaccia da cui eredita la classe LinkedList, che già conosci, quindi utilizzeremo questa implementazione.
In questo modo, si utilizza l'interfaccia come tipo dell'oggetto, ma l'implementazione dell'oggetto sarà LinkedList perché rappresenta una specifica implementazione di questo oggetto. (Ricorda che non è possibile creare oggetti basati su un'interfaccia).
Esempio:
Example.java
1234// `LinkedList` as implementation of the `List` interface: List<T> list = new LinkedList<>(); // `LinkedList` as implementation of the `Queue` interface: Queue<T> queue = new LinkedList<>();
In questo modo, è possibile rendere l'applicazione molto flessibile utilizzando varie implementazioni della stessa interfaccia.
Ma torniamo ai metodi di gestione della Queue.
Metodi
Alcuni dei principali metodi dell'interfaccia Queue sono:
add(element): aggiunge un elemento alla coda, lanciando un'eccezione se l'operazione non è possibile;offer(element): aggiunge un elemento alla coda, restituendotruese ha successo ofalsealtrimenti.
Si può notare che questi metodi svolgono essenzialmente la stessa funzione. Tuttavia, la differenza principale è la sicurezza del metodo offer. In caso di aggiunta non corretta di un elemento, il metodo offer non lancerà un'eccezione e non interromperà l'esecuzione del programma.
Tuttavia, al momento questa caratteristica non è di grande interesse, poiché una normale Queue non ha limiti. Esiste però una struttura chiamata BlockingQueue, che prevede una restrizione sul numero di elementi; in tal caso, questi metodi avranno una differenza significativa.
Vediamo un esempio:
Main.java
1234567891011121314package com.example; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Main { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(2); queue.add("One"); queue.add("Two"); queue.add("Three"); System.out.println("Queue: " + queue); } }
Come puoi vedere, quando si utilizza il metodo add() e si tenta di aggiungere un elemento che non trova spazio nella coda, il programma genera un errore, terminando l'esecuzione in modo imprevisto.
Proviamo la stessa operazione ma con un metodo più sicuro — offer():
Main.java
1234567891011121314package com.example; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Main { public static void main(String[] args) { BlockingQueue<String> queue = new LinkedBlockingQueue<>(2); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); System.out.println("Queue: " + queue); } }
Come puoi vedere, ora l'elemento non è stato aggiunto alla coda, ma non è stata nemmeno generata un'eccezione. Quindi, possiamo considerare che l'errore è stato gestito in modo appropriato.
È possibile gestire le eccezioni in modo diverso utilizzando una struttura come try-catch, ma ne parleremo più avanti.
Metodi di Rimozione
remove(): rimuove e restituisce l'elemento dall'inizio della coda, generando un'eccezione se la coda è vuota;poll(): rimuove e restituisce l'elemento dall'inizio della coda, restituendonullse la coda è vuota.
Questi metodi svolgono esattamente la funzione come se la prima persona nella coda entrasse nel negozio e lasciasse la coda. Qui entra in gioco il principio FIFO (First In, First Out). In altre parole, l'elemento che è stato aggiunto per primo alla coda sarà il primo ad essere rimosso.
Qui puoi anche osservare la differenza tra questi due metodi. Il metodo poll() viene utilizzato più spesso rispetto a remove() perché è più sicuro e non genera eccezioni.
Vediamo un esempio:
Main.java
123456789101112131415package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); System.out.println("Queue: " + queue); queue.remove(); queue.remove(); System.out.println("Queue after removal operation: " + queue); } }
Come puoi vedere, il programma genera una NoSuchElementException perché si sta tentando di rimuovere un elemento da una coda vuota.
Per evitare tale eccezione, è preferibile utilizzare il metodo poll():
Main.java
123456789101112131415package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); System.out.println("Queue: " + queue); queue.poll(); queue.poll(); System.out.println("Queue after removal operation: " + queue); } }
Ora, abbiamo rimosso in modo sicuro un elemento dalla coda e nessuna eccezione è stata generata quando si è tentato di rimuovere un elemento da una lista vuota.
La caratteristica di poll() che restituisce null può essere utilizzata, ad esempio, in un ciclo while().
Vediamo un esempio:
Main.java
1234567891011121314151617181920package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (queue.poll() != null) { queue.poll(); } System.out.println("Queue after removal operation: " + queue); } }
In questo modo, è possibile rimuovere tutti gli elementi dalla coda utilizzando un ciclo.
Ricorda che il primo elemento inserito nella coda è quello che viene rimosso! Ad esempio, nel caso dell'esempio sopra, l'elemento con il dato "One" è stato rimosso per primo.
Il principio FIFO è illustrato di seguito:
Main.java
123456789101112131415161718package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); queue.poll(); System.out.println("Queue after removal operation: " + queue); } }
Possiamo passare ai metodi che restituiscono il primo e l'ultimo elemento:
element(): restituisce, ma non rimuove, l'elemento all'inizio della coda, lanciando un'eccezione se la coda è vuota;peek(): restituisce, ma non rimuove, l'elemento all'inizio della coda, restituendonullse la coda è vuota.
L'utilizzo del metodo peek() rappresenta un approccio più affidabile e sicuro, poiché aiuta a evitare potenziali eccezioni.
Vediamo un esempio di utilizzo:
Main.java
12345678910111213141516package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); System.out.println("Queue: " + queue); System.out.println("The first element in the queue: " + queue.peek()); System.out.println("Queue after the `peek()` method: " + queue); } }
È possibile combinare questo metodo con altri metodi della coda.
Se si dispone di una coda con cinque elementi e si ha la necessità di rimuovere tutti gli elementi fino al quarto (incluso), vediamo l'implementazione di tale operazione:
Main.java
123456789101112131415161718192021package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (!queue.peek().equals("Four")) { queue.poll(); } queue.poll(); System.out.println("Queue after removal operation: " + queue); } }
È stato utilizzato un ciclo con una condizione basata sul metodo peek().
È possibile ottimizzare significativamente questo ciclo utilizzando il metodo contains(). Questo metodo restituisce true se l'elemento specificato è presente nella coda e false se non lo è.
Miglioriamo il codice sopra:
Main.java
1234567891011121314151617181920package com.example; import java.util.LinkedList; import java.util.Queue; public class Main { public static void main(String[] args) { Queue<String> queue = new LinkedList<>(); queue.offer("One"); queue.offer("Two"); queue.offer("Three"); queue.offer("Four"); queue.offer("Five"); System.out.println("Queue: " + queue); while (queue.contains("Four")) { queue.poll(); } System.out.println("Queue after removal operation: " + queue); } }
Qui impostiamo una singola condizione per il ciclo while. Siamo riusciti a rimuovere con successo tutti gli elementi fino e compreso l'elemento "Four".
1. Che cos'è una Queue in Java?
2. Quale interfaccia rappresenta una Queue nel Java Collections Framework?
3. Qual è lo scopo del metodo offer() nell'interfaccia Queue?
4. Cosa fa il metodo poll() nell'interfaccia Queue?
5. Quale classe nel package java.util.concurrent di Java rappresenta una coda bloccante con capacità limitata?
6. Cosa succede se si tenta di aggiungere un elemento a una coda piena utilizzando il metodo add()?
Grazie per i tuoi commenti!