Introduzione alle Liste
Le liste in Java sono fondamentali strutture dati che consentono di memorizzare, gestire e manipolare collezioni di oggetti in modo ordinato e flessibile. A differenza degli array, che hanno una dimensione fissa, le liste possono crescere e ridursi dinamicamente. Questo le rende ideali per situazioni in cui la quantità di dati da gestire può variare nel tempo. Java offre diverse implementazioni di liste, come
ArrayList
dijava.util
LinkedList
dijava.util
Implementazione manuale
mediante una “Relazione tra classi”
ciascuna con proprie caratteristiche e vantaggi specifici. Comprendere come utilizzare efficacemente le liste è essenziale per scrivere codice Java robusto e efficiente.
Confronto tra Array
e Liste
In Java, sia le liste che gli array sono utilizzati per memorizzare collezioni di elementi, ma presentano differenze fondamentali:
Vantaggi | Svantaggi | |
Array | ->Semplicità di gestione. ->Accesso diretto agli elementi. | ->Gestione statica del numero degli elementi. ->Difficoltà delle operazioni d’inserimento e cancellazione di elementi con criteri di ordinamento. |
Liste | ->Gestione dinamica del numero degli elementi. ->Facilità nelle operazioni d’inserimento e cancellazione di elementi anche in presenza di criteri di ordinamento. | ->Maggiore complessità di gestione rispetto all’array. ->Struttura ad accesso strettamente sequenziale. |
Tipi di implementazione: Le Classi del package java.util
Il collections framework
di Java ci offre varie implementazioni delle liste, più in particolare sono note le Classi ArrayList e LinkedList che ci permettono di implementare una Lista, seguono le differenze tra le due classi:
- ArrayList:
- Utilizza un array dinamico per memorizzare gli elementi.
- Gli elementi possono essere visionati direttamente tramite l’indice.
- È efficiente per l’accesso casuale e l’iterazione sequenziale.
- L’aggiunta o la rimozione di elementi in posizioni intermedie può richiedere la ridimensionamento dell’array, il che può essere costoso in termini di prestazioni.
- È più adatto per le situazioni in cui l’accesso casuale è frequente e la modifica della lista è meno frequente.
- LinkedList:
- Utilizza una lista collegata per memorizzare gli elementi.
- Ogni elemento è collegato al successivo tramite un riferimento.
- È efficiente per l’inserimento e la rimozione in posizioni intermedie.
- L’accesso casuale è meno efficiente poiché richiede di attraversare la lista dall’inizio.
- È più adatto per le situazioni in cui l’inserimento e la rimozione in posizioni intermedie sono frequenti.
Di questi due metodi illustrati ne analizzeremo l’implementazione pratica di uno soltanto ovvero il LinkedList
.
Implementazione mediante la classe LinkedList
Supponiamo che ci venga commissionata la creazione di un programma che deve gestire la lista delle persone invitate ad un evento, per ogni persona verranno salvati i dati anagrafici principali (nome, cognome, età), di seguito il Diagramma UML

La classe Persona e la MainClass sono associate in quanto nella MainClass troviamo l’istanziazione di oggetti della classe Persona, quindi la MainClass e la Classe Persona comunicano tra di loro.
Spiegazione della relazione tra le due classi
Nella classe Persona troviamo la definizione di tre Attributi:
nome
di tipoString
cognome
di tipoString
eta
di tipoint
Ovviamente gli attributi sono private
in quanto si rispetta la proprietà dell’Incapsulamento delle OOP quindi vengono implementati tutti i setter e getter necessari. Segue il codice della classe persona:
package pacchetto;
/**
* Classe per la gestione dei dati anagrafici di una persona
* @author Mario Lazzaro, Aurelio Costigliola
*/
public class Persona {
private String nome;
private String cognome;
private int eta;
/**
* Costruttore con parametri
* @param nome Nome della persona
* @param cognome Cognome della persona
* @param eta Età della persona
*/
public Persona(String nome, String cognome, int eta) {
this.nome = nome;
this.cognome = cognome;
this.eta = eta;
}
/**
* Costruttore copia
* @param oggetto Oggetto della Classe Persona da copiare
*/
public Persona(Persona oggetto) {
this.nome = oggetto.getNome();
this.cognome=oggetto.getCognome();
this.eta=oggetto.getEta();
}
//getter
public String getNome() {
return nome;
}
public String getCognome() {
return cognome;
}
public int getEta() {
return eta;
}
//setter
public void setNome(String nome){
this.nome = nome;
}
public void setCognome(String cognome){
this.cognome = cognome;
}
public void setEta(int eta){
this.eta = eta;
}
/**
* Metodo per la stampa a schermo di tutti gli attributi dell'oggetto
*/
public void printAll() {
System.out.println("----------------");
System.out.println("Nome : "+nome);
System.out.println("Cognome : "+cognome);
System.out.println("età : "+eta);
System.out.println("----------------");
}
}
Adesso riportiamo il codice della MainClass dove andremo ad utilizzare la classe LinkedList:
package pacchetto;
import java.util.LinkedList;
public class MainClass {
public static void main(String[] args) {
//Dichiarazione della lista mediante la classe 'LinkedList'
LinkedList<Persona> lista = new LinkedList<Persona>();
lista.add(new Persona("mario","Lazzaro",18));
lista.add(new Persona("mario","Rossi",28));
lista.add(new Persona("Pasquale Pio","De Vita",17));
System.out.println("Stampo l'ultimo nodo della lista:");
lista.getLast().printAll();
System.out.println("Stampo il primo nodo:");
lista.getFirst().printAll();
System.out.println("Stampo il secondo nodo nella lista:");
lista.get(1).printAll();
System.out.println("\n \nStampo tutti i nodi della lista:");
for(int i=0; i<lista.size();i++) {
lista.get(i).printAll();
}
}
}
Nel main() abbiamo dichiarato la nostra lista mediante l’utilizzo della classe LinkedList che segue la seguente sintassi:
LinkedList<Classe_del_dato_da_gestire> nome_lista = new LinkedList<Classe_del_dato_da_gestire>()
Dal JavaDoc della classe ricaviamo i metodi che possiamo applicare alla lista, segue la tabella riassuntiva dei metodi disponibili:
Method | Description |
---|---|
add(int index, E element) | This method Inserts the specified element at the specified position in this list. |
add(E e) | This method Appends the specified element to the end of this list. |
addFirst(E e) | This method Inserts the specified element at the beginning of this list. |
addLast(E e) | This method Appends the specified element to the end of this list. |
clear() | This method removes all of the elements from this list. |
clone() | This method returns a shallow copy of this LinkedList. |
contains(Object o) | This method returns true if this list contains the specified element. |
get(int index) | This method returns the element at the specified position in this list. |
getFirst() | This method returns the first element in this list. |
getLast() | This method returns the last element in this list. |
indexOf(Object o) | This method returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. |
lastIndexOf(Object o) | This method returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element. |
offerFirst(E e) | This method Inserts the specified element at the front of this list. |
offerLast(E e) | This method Inserts the specified element at the end of this list. |
remove() | This method retrieves and removes the head (first element) of this list. |
remove(int index) | This method removes the element at the specified position in this list. |
remove(Object o) | This method removes the first occurrence of the specified element from this list if it is present. |
removeFirst() | This method removes and returns the first element from this list. |
removeFirstOccurrence(Object o) | This method removes the first occurrence of the specified element in this list (when traversing the list from head to tail). |
removeLast() | This method removes and returns the last element from this list. |
set(int index, E element) | This method replaces the element at the specified position in this list with the specified element. |
size() | This method returns the number of elements in this list. |
toArray() | This method returns an array containing all of the elements in this list in proper sequence (from first to last element). |
toString() | This method returns a string containing all of the elements in this list in proper sequence (from first to the last element), each element is separated by commas and the String is enclosed in square brackets. |
Implementazione manuale mediante la classe "La Relazioni tra classi"
Adesso analizziamo l’implementazione manuale delle liste in Java mediante una Relazione tra Classi che sfrutta 3 classi:
- Classe
Lista
(la classe che in cui verrà implementata la logica di funzionamento della lista ) - Classe
Nodo
(la classe che in cui verrà implementata la definizione del Nodo ) - Classe
Dato
(la classe che in cui verrà implementata la Classe del Dato da gestire )
Supponiamo che ci venga commissionato lo sviluppo di un applicativo per la gestione dell’anagrafica di un comune in cui per ogni persona venga registrato nome, cognome ed età. Analizziamo il problema e riportiamo di seguito il Diagramma UML :

Da come possiamo vedere troviamo 4 classi, per la gestione della lista si evidenziano le seguenti 3 classi:
Anagrafica
(Classe corrispondente alla Classe Lista)Nodo
(Classe corrispondente alla Classe Nodo)Persona
(Classe corrispondente alla Classe Dato)
La Classe Anagrafica
contiene tutti i metodi per la visita,inserimento ed eliminazione di un Nodo nella lista; La Classe dipende dalla Classe Persona
ed è un’aggregazione della Classe Nodo
.
La Classe Persona
si occupa di definire l’oggetto da gestire nella lista (in questo caso una persona con nome, cognome ed età), essa compone la Classe Nodo
La Classe Nodo
si occupa di definire il nodo della lista, essa composta dalla Classe Persona
ed aggregante della Classe Anagrafica
inoltre è un’aggregazione di se stessa.
La Classe MainClass contiene il main()
e si occupa della gestione del menu()
della consolle, inoltre si Occupa della chiamata dei metodi della classe Anagrafica
e del istanziazione degli oggetti della Classe Persona
da passare ai metodi di inserimento della Classe Anagrafica
, quindi è associata alle Classi Anagrafica
e Persona
segue il codice della Classe Persona
package pacchetto;
/**
* Classe per la gestione dei dati anagrafici di una persona
* @author Mario Lazzaro, Aurelio Costigliola
*/
public class Persona {
private String nome;
private String cognome;
private int eta;
/**
* Costruttore con parametri
* @param nome Nome della persona
* @param cognome Cognome della persona
* @param eta Età della persona
*/
public Persona(String nome, String cognome, int eta) {
this.nome = nome;
this.cognome = cognome;
this.eta = eta;
}
/**
* Costruttore copia
* @param oggetto Oggetto della Classe Persona da copiare
*/
public Persona(Persona oggetto) {
this.nome = oggetto.getNome();
this.cognome=oggetto.getCognome();
this.eta=oggetto.getEta();
}
//getter
public String getNome() {
return nome;
}
public String getCognome() {
return cognome;
}
public int getEta() {
return eta;
}
//setter
public void setNome(String nome){
this.nome = nome;
}
public void setCognome(String cognome){
this.cognome = cognome;
}
public void setEta(int eta){
this.eta=eta;
}
/**
* Metodo per la stampa a schermo di tutti gli attributi dell'oggetto
*/
public void printAll() {
System.out.println("----------------");
System.out.println("Nome : "+nome);
System.out.println("Cognome : "+cognome);
System.out.println("età : "+eta);
System.out.println("----------------");
}
}
Come possiamo vedere la Classe Persona è analoga alla Classe Persona implementata mediante la classe LinkedList, segue quindi il codice della Classe Nodo
:
package pacchetto;
/**
* Classe per definizione dei Nodi di una lista
* @author Mario Lazzaro, Aurelio Costigliola
*/
public class Nodo {
private Persona info;
private Nodo link;
/**
* Costruttore con parametri del nodo
* @param oggetto
*/
public Nodo(Persona oggetto) {
info = new Persona(oggetto);
link = null;
}
//getter
public Nodo getNodo(){
return new Nodo(this.getInfo());
}
public Persona getInfo() {
return new Persona(info);
}
public Nodo getLink() {
return link;
}
//setter
public void setLink(Nodo link) {
this.link = link;
}
public void setInfo(Persona info) {
this.info = info;
}
}
Ogni Nodo avrà due Attributi:
info
di tipo Persona che conterrà l’informazione (in questo caso l’oggetto della classe persona)link
di tipo Nodo (che conterrà la reference del nodo successivo)

Segue quindi il codice della classe anagrafica:
package pacchetto;
import java.util.Scanner;
/**
* Anagrafica
* @author Mario Lazzaro, Aurelio Costigliola
*/
public class Anagrafica {
private Nodo head;
private int elementi;
/**
*Costruttore della classe anagrafica
*/
public Anagrafica(){
head = null;
elementi=0;
}
//metodi utili
Scanner input = new Scanner(System.in);
private void sysPause(){
System.out.println("Premere un tasto per continuare...");
input.nextLine();
}
private static void clearScreen() {
System.out.print("\033[H\033[2J");
System.out.flush();
}
/**
* Mostra tutta l'Anagrafica
*/
public void mostaAnagrafica(){
System.out.flush();
Nodo p = head;
while(p != null){
p.getInfo().printAll();
p = p.getLink();
}
sysPause();
}
/**
* Mostra tutte le persone in base al nome
* @param nome nome da fornire
*/
public void mostaAnagraficabyNome(String nome){
System.out.flush();
Nodo nodo=head;
while(nodo != null){
if(nodo.getInfo().getNome().equals(nome)){
nodo.getInfo().printAll();
}
nodo=nodo.getLink();
}
}
/**
* Mostra tutte le persone in base al cognome fornito
* @param cognome cognome da fornire
*/
public void mostaAnagraficabyCognome(String cognome){
System.out.flush();
Nodo nodo=head;
while(nodo != null){
if(nodo.getInfo().getCognome().equals(cognome)){
nodo.getInfo().printAll();
}
nodo=nodo.getLink();
}
sysPause();
}
/**
* Mostra tutte le persone in base alla età fornita
* @param eta età da fornire
*/
public void mostaAnagraficabyEta(int eta){
System.out.flush();
Nodo nodo=head;
while(nodo != null){
if(nodo.getInfo().getEta() == eta){
nodo.getInfo().printAll();
}
nodo=nodo.getLink();
}
sysPause();
}
/**
* Mostra tutte le persone in base al nome fornito
* @param iniziale
*/
public void mostaAnagraficabyInizialeNome(String iniziale){
Nodo nodo=head;
boolean stampato=false;
clearScreen();
System.out.println("Procedo alla ricerca e alla stampa delle persone individuate: ");
while(nodo != null){
if(nodo.getInfo().getNome().startsWith(iniziale)){
nodo.getInfo().printAll();
stampato=true;
}
nodo=nodo.getLink();
}
if(stampato==false){
System.err.println("Errore:Nessuna persona trovata");
}
sysPause();
}
/**
* Inserisce in testa un nodo
* @param persona
*/
public void inserisciInTestaPersona(Persona persona){
Nodo n = new Nodo(persona); //creazione di un nodo
n.setLink(head); //setto il link del nuovo nodo verso l'attuale head
head = n; //ora che ho settato il link del nuovo nodo, setto il nuovo head a n
elementi++; //autoincremento la variabile elementi
}
/**
* Inserisce in coda un nodo
* @param persona
*/
public void inserisciInCodaPersona(Persona persona){
Nodo p = head;
Nodo n = new Nodo(persona);
if(p==null)
inserisciInTestaPersona(persona);
else{
while (p.getLink()!=null){
p=p.getLink();
}
n.setLink(null);
p.setLink(n);
elementi++;//autoincremento la variabile elementi
}
}
/**
* Eliminatore di nodi in testa
*/
public void eliminaInTesta(){
if(head==null){
return;
}
head = head.getLink();
elementi--;
}
/**
* Eliminatore di nodi in coda
*/
public void eliminaInCoda(){
if(head == null)
return;
if(head.getLink() == null){
eliminaInTesta();
}else{
Nodo p = head;
Nodo pp=head.getLink();
while(pp.getLink() != null){
p=pp;
pp=pp.getLink();
}
p.setLink(null);
elementi--;
}}
/**
* Eliminatore mediante il cognome della persona
* @param cognome Cognome della persona da eliminare
*/
public void eliminaByCognome(String cognome) {
Nodo nodo = head;
Nodo[] elementistampati = new Nodo[elementi];
int counter = 0;
for (int i = 0; i < elementi; i++) {
if (nodo.getInfo().getCognome().equalsIgnoreCase(cognome)) {
elementistampati[counter] = nodo;
System.out.println("N:" + counter);
nodo.getInfo().printAll();
counter++;
}
nodo = nodo.getLink();
}
if (counter == 0) {
System.out.println("Nessun nodo trovato con il cognome specificato.");
return;
}
System.out.println("Inserire il numero del nodo da eliminare:");
int scelta = input.nextInt();
if (scelta < 0 || scelta >= counter) {
System.out.println("Scelta non valida.");
return;
}
Nodo nodoDaEliminare = elementistampati[scelta];
if (nodoDaEliminare == head) {
eliminaInTesta();
} else if (nodoDaEliminare.getLink() == null) {
eliminaInCoda();
} else {
Nodo precedente = head;
while (precedente.getLink() != nodoDaEliminare) {
precedente = precedente.getLink();
}
precedente.setLink(nodoDaEliminare.getLink());
elementi--;
}
System.out.println("Eliminato: " + nodoDaEliminare.getInfo().getNome());
}
}
Seguono i file per la riproduzione del codice trattato in questo “How to”: