La classe Scanner

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

  1. InputStream, utile in quei casi in cui, per esempio, si abbia la necessità di procurarsi degli input da tastiera (l’oggetto System.in, si ricorda, è di classe InputStream);
  2. String, in quei casi in cui sia necessario procurarsi degli input da un oggetto di classe String, ossia a partire da una stringa;
  3. File, in questo caso l’oggetto ottenuto può essere utilizzato per procurarsi degli input 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ù utili di questa classe:

  • int nextInt(), legge un numero intero e lo restituisce al chiamante;
  • double nextDouble(), legge un numero reale e lo restituisce al chiamante;
  • String nextLine(), legge una linea di testo e la restituisce al chiamante;
  • String next(), legge un “token” (un blocco di testo, una sottostringa), ossia una sequenza di caratteri contigui senza delimitatori, e lo restituisce al chiamante; questo metodo considera come delimitatori di sottostringhe gli spazi, i caratteri di tabulazione e i caratteri di newline;
  • 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 linea, 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 in cui è utilizzato il delimitatore di default, ossia lo spazio, dalla quale vengono estratti solo gli interi saltando i restanti token. Il risultato prodotto sarà:

1
56
78
1092
100

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

L’esempio precedente produce in output:

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: