Classi della libreria Java
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 base | Wrapper |
| int | Integer |
| float | Float |
| double | Double |
| char | Char |
| boolean | Boolean |
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:
| Metodo | Descrizione | Esempio |
|---|---|---|
Math.abs(x) | Valore assoluto | Math.abs(-5) → 5 |
Math.max(a, b) | Valore massimo tra due numeri | Math.max(3, 7) → 7 |
Math.min(a, b) | Valore minimo tra due numeri | Math.min(3, 7) → 3 |
Math.pow(a, b) | Potenza: a elevato alla b | Math.pow(2, 3) → 8.0 |
Math.sqrt(x) | Radice quadrata | Math.sqrt(9) → 3.0 |
Math.round(x) | Arrotonda al numero intero più vicino | Math.round(3.6) → 4 |
Math.floor(x) | Arrotonda per difetto | Math.floor(3.9) → 3.0 |
Math.ceil(x) | Arrotonda per eccesso | Math.ceil(3.1) → 4.0 |
e trigonometriche:
| Metodo | Descrizione | Esempio |
|---|---|---|
Math.sin(x) | Seno (x in radianti) | Math.sin(Math.PI / 2) |
Math.cos(x) | Coseno | Math.cos(0) |
Math.tan(x) | Tangente | Math.tan(Math.PI / 4) |
Math.asin(x) | Arco-seno (risultato in radianti) | Math.asin(1) |
Math.acos(x) | Arco-coseno | Math.acos(0) |
Math.atan(x) | Arco-tangente | Math.atan(1) |
Math.toRadians(gradi) | Converte gradi in radianti | Math.toRadians(180) |
Math.toDegrees(radianti) | Converte radianti in gradi | Math.toDegrees(Math.PI) |
I numeri random si generano così:
float valore = Math.random(); // valore tra 0 e 1Date
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 eccezione | Descrizione |
|---|---|
| ArrayIndexOutOfBoundException | si cerca di accedere ad un indice esterno alla dimensione dell’array |
| StringIndexOutOfBoundsException | si cerca di accedere ad un indice esterno alla dimensione della stringa |
| ArithmeticException | Divisione per zero |
| IllegalArgumentException | Si cerca di passare un argomento non valido ad un metodo |
| NumberFormatException | Conversione 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:
| Eccezione | Descrizione |
|---|---|
| IOException | errore di input/output su file |
| FileNotFoundException | file non trovato |
| SQLException | Errore 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.
