La classe Scanner

La classe Scanner rappresenta la soluzione più semplice per realizzare in Java un input da uno stream di caratteri. La classe Scanner appartiene al package java.util e i suoi oggetti sono in grado di individuare e interpretare i tipi primitivi e le stringhe presenti all’interno di uno stream di caratteri. Essa presenta diversi costruttori che permettono di ottenere un oggetto di tipo Scanner a partire da oggetti di altri tipi, quali ad esempio:

  1. InputStream, utile in quei casi in cui, per esempio, si debba leggere da tastiera (l’oggetto System.in, si ricorda, è di tipo InputStream).
  2. String, utile in quei casi in cui sia necessario procurarsi degli input da una stringa.
  3. File, utile in quei casi in cui l’input proviene da un file di testo.

Per approfondimenti al solito si rimanda alla documentazione ufficiale del linguaggio Java (link), di seguito vediamo solo alcuni esempi di utilizzo per i primi due casi: lettura da tastiera e da stringhe, per il terzo caso della lettura da un file di testo, invece, si rimanda al seguente link. Prima però accenniamo a quali sono alcuni dei metodi più utilizzati di questa classe.

(Si tenga presente che la classe Scanner suddivide lo stream dei caratteri in token, cioè in spezzoni di stringhe separate dai caratteri delimitatori. I caratteri delimitatori di default sono: gli spazi, i caratteri di tabulazione e i caratteri di newline).

  • int nextInt(): legge il token successivo interpretandolo come un numero intero e lo restituisce al chiamante, o lancia un eccezione di tipo InputMismatchException se il token non è un intero.
  • double nextDouble(): legge il token successivo interpretandolo come un numero reale e lo restituisce al chiamante, o lancia un eccezione di tipo InputMismatchException se il token non è un reale.
  • String nextLine(): legge la riga di testo (successiva) e la restituisce al chiamante.
  • String next(): legge il successivo token senza delimitatori e lo restituisce al chiamante.
  • boolean hasNextInt(): restituisce vero se il prossimo token può essere interpretato come un numero intero, falso altrimenti.
  • boolean hasNextDouble(): restituisce vero se il prossimo token può essere interpretato come un numero reale, falso altrimenti.
  • boolean hasNextLine(): restituisce vero se in input è disponibile una ulteriore riga, falso altrimenti.
  • boolean hasNext(): restituisce vero se in input è disponibile un ulteriore token, falso altrimenti.
  • Scanner useDelimiter(String): modifica il delimitatore dei token, dove la stringa passata come parametro può essere una espressione regolare (vedi esempio più avanti).

Il caso più tipico di utilizzo di un oggetto di classe Scanner è quello che utilizza il metodo nextLine() per leggere una riga intera.

Vediamo anche alcuni esempi di utilizzo della classe Scanner con gli altri metodi:

Nell’esempio di sopra vengono prelevati da tastiera due numeri e vengono sommati. Il tutto è stato inserito in un blocco try-catch-finally poiché gli input forniti potrebbero non essere degli interi e in tal caso viene lanciata un’eccezione di classe InputMismatchException. In questo esempio viene utilizzato anche il metodo close() che permette di rilasciare le risorse occupate dall’oggetto di classe Scanner creato.

Nell’esempio di sopra si ha una stringa che utilizza un delimitatore di default (lo spazio), dalla quale vengono estratti solo gli interi saltando i restanti token. L’output ottenuto è il seguente:

1
56
78
1092
100

Il delimitatore di default può essere modificato tramite il metodo useDelimiter(), come nell’esempio seguente:

L’esempio precedente produce l’output seguente:

100
120
300
80

NOTA BENE. Attenzione, l’esempio precedente funziona solo se i numeri interi sono separati esattamente da un solo carattere di punto e virgola. Se si vuole che funzioni anche nel caso in cui a separarli ci siano più caratteri diversi, compreso gli spazi, bisogna passare al metodo un’espressione regolare, argomento questo complesso per il quale si rimanda alla documentazione del linguaggio. Qui si fornisce solo la soluzione nel caso tra i numeri interi, oltre al punto e virgola, ci siano anche degli spazi. In questo caso la stringa da passare al metodo è : “\s*;\s*”. Il primo backslash nell’espressione indica che quello che segue è un carattere speciale, ossia l’espressione s* che vuol dire “da 0 a un numero a piacere di spazi“.

P.S. Per risolvere un problema di estrazione di token da una stringa come il precedente, può essere più conveniente o sfruttare direttamente i metodi della classe String, come ad esempio i metodi split() e trim(), o riccorre alla classe StringTokenizer sftuttando i metodi hasMoreToken() e nextToken(), per i quali si rimanda alla documentazione ufficiale del linguaggio Java (link). Si riporta qui sotto per comodità il codice di un semplice esempio di utilizzo per entrambe le soluzioni citate prima:

Il codice di sopra produce l’output seguente:
3A
4A
5A

3A
4A
5A