< Home
Stampa

Classi della libreria Java

Sommario

La libreria standard Java contiene un insieme di classi utili nelle applicazioni. Vediamo quelle più importanti.

Classi wrapper

Nella lezione precedente abbiamo introdotto i tipi base. I tipi base non sono oggetti, sono semplici contenitori di valori. Java permette però di usare degli oggetti che corrispondono ai tipi base, ma sono veri e propri oggetti detti Wrapper (“contenitori”):

Tipo baseWrapper
intInteger
floatFloat
doubleDouble
charChar
booleanBoolean

Gli oggetti Wrapper:

  • non hanno bisogno della parola chiave new. E’ quindi possibile assegnare come ad esempio Integer i = 0;
    La parola chiave new non è necessaria, ma è sempre possibile usarla.
  • si comportano come tipi riferimento e non come tipi valore.
  • siccome stanno nello Heap sono sempre preferibili quando si usano all’interno di liste di oggetti, come gli array (che vedremo qui sotto).

Array

Andiamo ad approfondire meglio l’array, già introdotto nella prima lezione.

Un Array è una classe che rappresenta una lista di variabili dello stesso tipo. Vediamo qualche esempio di dichiarazione:

float[] lista = new float[10]; // dichiara un array di 10 elementi con valore 0 di default;
Persona[] persone = new Persona[10]; // crea un array di 10 oggetti di tipo Persona
Integer[] elementi = {1,2,3,4,5}; // dichiarazione tramite literal
int matrix[][] = new int[6][8]; // matrice bidimensionale.

Come si vede la coppia di parentesi quadre davanti al tipo di dato lo definisce come array. Possiamo definire un array multidimensionale aggiungendo altre coppie di parentesi.

Per istanziarlo possiamo darne o la dimensione o indicare con un literal direttamente i valori. Se dichiariamo un array di tipo oggetto, gli oggetti non sono automaticamente instanziati. Non è possibile modificare la dimensione di un array dopo averlo creato.

persone[0] = new Persona("Mario", "Rossi");
persone[0].print();

for (int i=0; i<lista.length; i++) {
  System.out.println(lista[i]);
}

for (int i : lista) {
   System.out.println(i);
}
  • La proprietà length indica la dimensione.
  • il costruto for (elemento : array) { … } permette di scorrere gli elementi di un array

La libreria java.util.Arrays fornisce un insieme di funzioni utili per lavorare sugli array. Vediamo un esempio completo:

import java.util.Arrays;

public class ArrayApplication {

    public static void main(String[] args) {
        int[] lista = {9,4,2,5,1,8,6};
        Arrays.sort(lista);
        System.out.println("Lista: " + Arrays.toString(lista));
        int indice = Arrays.binarySearch(lista, 2);
        System.out.println(indice);
        int[] copia = Arrays.copyOf(lista, lista.length);
        System.out.println("Copia: " + Arrays.toString(copia));
        boolean uguali = Arrays.equals(lista, copia);
        System.out.println(uguali);
    }
}

Riassumendo:

  • sort() ordina un array
  • toString() stampa l’array in modo gradevole
  • binarySearch(array, elemento) restituisce l’indice dell’elemento se trovato, valore negativo altrimenti
  • copyOf(array, numero elementi) crea una deep copy dell’array
  • equals(array1, array2) confronta tutti gli elementi uno per uno e restituisce un booleano

For con array

Java prevede un costrutto for specifico per gli array e tutte le liste. La struttura la vediamo nel seguente esempio:

int[] numeri = {10, 20, 30, 40, 50};
int somma = 0;

for (int numero : numeri) {
  somma += num;
}

Stringhe

Le stringhe, già viste nella prima lezione, rappresentano un gruppo di caratteri e si usano per rappresentare il testo. Sono un tipo di dati particolare per le seguenti ragioni che vediamo con qualche esempio:

        String s1 = "ciao";
        System.out.println(s1);
        String s2 = s1;
        System.out.println("Lunghezza: "+ s1.length());
        System.out.println(s1.charAt(2));
        System.out.println(s1.concat(s2));
        s1 = "Ciao Mario";
        System.out.println(s1.substring(5));
        System.out.println(s1.substring(0, 4));
        String[] chars = s1.split("");
        boolean equal = s1.equals(s2); 
  • sono oggetti, ma per essere creati non hanno bisogno della parola chiave new String, è sufficiente assegnarli come un literal. La parola chiave new è comunque possibile.
  • Analogamente si possono stampare direttamente con System.out.println per esempio.
  • La copia di una stringa (assegnazione) produce una nuova stringa identica, è quindi una deep copy.
  • E’ possibile avere la lunghezza con length().
  • Si accede al singolo carattere con charAt().
  • Si possono concatenare due stringhe con concat(stringa1, stringa2).
  • SI può ottenere una nuova stringa con concat(inizio) oppure concat(inizio, fine).
  • Si può creare anche un array di char con split(carattere separatore).
  • per confrontare due stringhe si usa equals.

Funzioni matematiche

Qui un elenco di funzioni matematiche:

MetodoDescrizioneEsempio
Math.abs(x)Valore assolutoMath.abs(-5) → 5
Math.max(a, b)Valore massimo tra due numeriMath.max(3, 7) → 7
Math.min(a, b)Valore minimo tra due numeriMath.min(3, 7) → 3
Math.pow(a, b)Potenza: a elevato alla bMath.pow(2, 3) → 8.0
Math.sqrt(x)Radice quadrataMath.sqrt(9) → 3.0
Math.round(x)Arrotonda al numero intero più vicinoMath.round(3.6) → 4
Math.floor(x)Arrotonda per difettoMath.floor(3.9) → 3.0
Math.ceil(x)Arrotonda per eccessoMath.ceil(3.1) → 4.0

e trigonometriche:

MetodoDescrizioneEsempio
Math.sin(x)Seno (x in radianti)Math.sin(Math.PI / 2)
Math.cos(x)CosenoMath.cos(0)
Math.tan(x)TangenteMath.tan(Math.PI / 4)
Math.asin(x)Arco-seno (risultato in radianti)Math.asin(1)
Math.acos(x)Arco-cosenoMath.acos(0)
Math.atan(x)Arco-tangenteMath.atan(1)
Math.toRadians(gradi)Converte gradi in radiantiMath.toRadians(180)
Math.toDegrees(radianti)Converte radianti in gradiMath.toDegrees(Math.PI)

I numeri random si generano così:

float valore = Math.random(); // valore tra 0 e 1

Date

Java supporta le date con un insieme di classi apposite. Vediamo gli esempi:

import java.time.*;;
...

LocalDate oggi = LocalDate.now();              // Data corrente
LocalDate dataSpecifica = LocalDate.of(2025, 7, 15);
LocalDateTime adesso = LocalDateTime.now();
LocalDateTime dataOra = LocalDateTime.of(2025, 7, 15, 14, 30);

LocalDate domani = oggi.plusDays(1);
LocalDate settimanaProssima = oggi.plusWeeks(1);
LocalDate ieri = oggi.minusDays(1);

if (dataSpecifica.isBefore(oggi)) {
    System.out.println("La data è nel passato");
}

Come si può vedere:

  • LocalDate e LocalDateTime indicano rispettivamente data senza ora e data con ora.
  • E’ possibile creare la data dall’istante attuale o passando anno, mese, giorno, ora e minuto.
  • Si possono sommare ore, minuti, giorni, settimane, mesi ed anni ad una data.
  • E’ possibile confrontare date.

Si può anche generare una data da una stringa:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
String dataFormattata = oggi.format(formatter);  // "15/07/2025"

LocalDate parsed = LocalDate.parse("31/12/2025", formatter);

File

Per eseguire la scrittura di un file di testo esistono numerose classi, per le nostre lezioni useremo PrintWriter.

PrintWriter pw = new PrintWriter("file.txt");
pw.println("Questo è un testo di prova");
pw.close();

Per eseguire la lettura invece si può usare Scanner, questa volta per leggere da file.

Scanner file = new Scanner(new File("file.txt"));
while (file.hasNextLine()) {
    System.out.println(file.nextLine());
 }
 file.close();

Eccezioni

Quando si eseguono istruzioni o si manipolano oggetti fuori dal normale flusso di programa, ad esempio quando si apre un file, o si cerca di accedere ad un elemento di un array vuoto, ci si può trovare di fronte ad una problematica non gestibile nel normale algoritmo del programma.

Java intercetta questi eventi “eccezionali” con generando oggetti della gerarchia di classi Exception, detti appunto “Eccezioni”.

Quando viene emessa una eccezione, il flusso del programma si interrompe e l’applicazione va in crash indicando all’utente in console perché c’è stato il crash e le sue cause.

try-catch

Il linguaggio però mette a disposizione un meccanismo per intercettare le eccezioni e quindi di gestirle senza crash. Il costrutto è il seguente:

try {
  codice che può provocare l'eccezione
} catch (Exception e) { 
   codice che gestisce l'eccezione
} finally {
   codice che viene eseguito in entrambi i casi
}

Vediamolo in dettaglio:

  • try circonda il blocco “a rischio”, ad esempio l’apertura di un file;
  • catch indica l’eccezione che può avvenire e il blocco che la gestirà
  • finally indica un blocco opzionale che verrà eseguito in qualsiasi caso (ad esempio per chiudere il file)

Lo vediamo con esempio:

try {
  Scanner file = new Scanner(new File("file.txt")); 
  while (file.hasNextLine()) {
      System.out.println(file.nextLine());
   }
   file.close();
} catch (Exception e) {
   System.out.println("Questo blocco viene eseguito se viene individuata una eccezione");
} finally {
  System.out.println("Questo blocco viene eseguito comunque, con o senza eccezione")
};

ViIl blocco try viene eseguito ma tenuto sotto controllo. Se nell’esecuzione viene sollevata una eccezione (ad esempio file non esiste), viene eseguito il blocco catch. Infine c’è il blocco opzionale finally che se presente viene eseguito comunque.

Ma quali sono le classi della gerarchia Exception?

Vi sono due tipi di Exception.

RuntimeException

Sono eccezioni che non richiedono una try-catch obbligatoria e rappresentano eccezioni legate ai dati. Ecco le più comuni:

Nome eccezioneDescrizione
ArrayIndexOutOfBoundExceptionsi cerca di accedere ad un indice esterno alla dimensione dell’array
StringIndexOutOfBoundsExceptionsi cerca di accedere ad un indice esterno alla dimensione della stringa
ArithmeticExceptionDivisione per zero
IllegalArgumentExceptionSi cerca di passare un argomento non valido ad un metodo
NumberFormatExceptionConversione da stringa a numero non riuscita

Checked Exception

Questa categoria richiede sempre una try-catch oppure la funzione che le contiene deve dichiarare che può generare eccezioni. Ad esempio:

returnType myFunction(args...) throws IOException { ... }

La parola chiave throws indica che la funzione non ha dentro una try catch ma che la funzione che la lancia dovrà contenerla (o a sua volta avere un throws che rimanda il problema alla funzione che la chiama, e così via fino al main). In ogni caso ci deve essere da qualche parte una try catch. Questo tipo di eccezioni sono generate da chiamate al sistema operativo.

Ecco le eccezioni più comuni:

EccezioneDescrizione
IOExceptionerrore di input/output su file
FileNotFoundExceptionfile non trovato
SQLExceptionErrore nella query al database

Sulle eccezioni bisogna fare attenzione a non abusarne, mettendo una try catch a tutto il codice e gestire così qualsiasi errore nell’applicazione. Le try catch hanno un costo prestazionale importante e vanno usate solo quando strettamente necessario. Va escluso quindi codice non strettamente a rischio.

Lettura e scrittura file

Per leggere un file di testo:

try {
  Path path = Path.of("file.txt");
  String content = Files.readString(path, StandardCharsets.UTF_8);
} catch (Exception e) {
  System.out.println("Errore di I/O in lettura");
} 

Il set di caratteri di norma è UTF_8, di norma va bene per la quasi totalità dei file di testo, se necessario un encoding diverso, consultare la guida ufficiale di Java.

Questo metodo funziona con file di testo di piccola dimensione.

Per scrivere un file di testo:

try {
   Path path = Path.of("file.txt");
   Files.write(path, content.getBytes());
} catch (Exception e) {
   System.out.println("Errore di I/O in scrittura");
}

Nella funzione sulle classi di libreria, vedremo altri metodi per leggere e scrivere files.