A. Veneziani - Commento al programma elementare “Ciao mondo !” e al programma
per effetturare la somma di due numeri letti in input
Spiegazione abbinata al listato test_io.java
public class test_io {
public static void main(String[] args) {
System.out.println("Ciao Mondo !");
}
}
Il listato presenta l’implementazione di una classe (test_io) dichiarata pubblica.
Questa indicazione comporta che la classe stessa sia richiamabile anche al di fuori del package ove si trova.
In questa classe è presente anche il metodo main(); tale metodo, se la classe ne è provvista, ossia se è
presente nel listato, viene attivata ogni volta che la classe di avvio del progetto viene richiamata. Tale classe
quindi dovrà sempre contenere un metodo main().
Una classe “di avvio” che non ha metodo main() produrrà perciò un errore.
Si può anche osservare che il metodo main è dichiarato in questo programma public.
Questo indica che esso è richiamabile da qualsivoglia punto di un altro programma, ossia che questo
metodo è visibile (richiamabile) ovunque, senza limitazioni.
Ciò si rende necessario, essendo lo stesso richiamato da un contesto esterno.
Si tratta anche di un metodo statico (static). Questo vuol dire che questo metodo, per essere usato, non
abbisogna che la classe relativa sia istanziata in un’oggetto.
Void, indica invece che il metodo main non rende valori. Esistono per contro metodi che ne rendono.
L’indicazione String[] args tra parentesi, indica la capacità del metodo main di rilevare in un apposito
vettore di stringhe I valori (parametri) inseriti al seguito del nome della classe di avvio, al momento del lancio
della applicazione Java.
In genere quindi si effettuerà, da riga di comando (finestra “Prompt dei comandi” in Windows):
c:\work\java\hello>
Ciao Alberto !
java
hello
Alberto
In questo caso abbiamo passato all’applicazione hello un parametro stringa (contente un nome di persona),
che viene poi riutilizzato dal programma stesso, nello svolgimento del suo codice (produrre ad esempio un
saluto personalizzato, ossia un saluto a quella determinata persona).
Tipicamente, per fissare le idee riguardo su tali tipi di classi si può tenere presente la classe Math, i cui
metodi (funzioni matematiche) sono tutti statici, ossia, in altre parole, per utilizzare tali metodi non è
necessario istanziare un oggetto Math.
Nessuno degli elementi sopra descritti del metodo main può essere tralasciato o alterato. Se ciò
succedesse, siccome la chiamata effettuata dalla JVM è verso un metodo che ha caratteristiche ben precise,
come quelle appunto indicate e non altre.
Segue l’invocazione alla classe System. Esso, tra altre funzioni, è preposto a controllare l’ I/O sui tre flussi
principali di dati, quali standard input, standard output e standard error (canale standard di uscita delle
segnalazioni di errore). Essa non viene istanziata ed infatti in essa viene usato, un campo statico (variabile
statica) di nome out.
Tale variabile, essendo statica, esiste abbinata alla classe, non agli oggetti.
Questa variabile, rappresenta nello specifico caso, un oggetto essa stessa, e specificamente un oggetto di
tipo PrintStream. Gli oggetti di questo tipo aprono dei canali per la scrittura dei dati, in questo caso la
scrittura su video (che è il dispositivo standard di output).
La classe possiede opportuni metodi, tra cui i metodi print e pritnln (quest’ultimo aggiunge dopo aver scritto
un ritorno a capo). Di questi metodi esistono varie versioni con tipo di parametro diverso da caso a caso.
Un meccanismo automatico interno, proprio dei linguaggi ad oggetti, permette di applicare il metodo print
adeguato, a seconda del tipo di dato presente come parametro.
Una volta svolte le istruzioni indicate nel metodo main, se non sussistono altri elementi attivi nel programma,
il programma termina automaticamente la sua esecuzione.
Commento ad un listato con operazioni di Input
/*
A. Veneziani - Programma che effettua I/O per calcolare una
semplice somma di interi
(Compilato con JDK 1.4.2)
*/
package io;
import java.io.*;
public class test_io2 {
public static void main(String[] args) {
InputStreamReader Isr;
BufferedReader Bfr;
String s1, s2;
int x, y, r;
// definisce come sorgente del flusso di input lo "standard input"
Isr = new InputStreamReader(System.in);
Bfr = new BufferedReader(Isr);
s1 = ""; s2 = "";
try
{
System.out.print("Leggi primo addendo: ");
s1 = Bfr.readLine();
System.out.print("Leggi secondo addendo: ");
s2 = Bfr.readLine();
}
catch (IOException ioe) {
};
x = Integer.valueOf(s1).intValue();
y = Integer.valueOf(s2).intValue();
r = x + y;
System.out.println("Il risultato e': " + r);
}
}
Il programma che andiamo ad analizzare si pone come scopo di sommare due numeri interi dopo averli letti
da console.
In questo listato vengono utilizzate 2 nuovi classi per realizzare l’input di dati (su una console a carattere),
ossia InputStreamReader e BufferedReader.
In effetti la classe BufferedReader è solo di supporto
all’attività di lettura, ossia la facilita e la potenzia, aggiungendo un buffer di lettura, come il suo nome del
resto dice. La lettura di se per se potrebbe essere effettuata anche con la sola classe InputStreamReader,
operando carattere, per carattere, ed effettuando opportuni cicli di lettura.
Al momento dell’istanza di InputStreamReader è necessario indicare l’origine dei dati in lettura:
Isr = new InputStreamReader(System.in);
In questo caso il flusso deriva da System.in, ossia, per quanto detto sopra per il listato precedente, dallo
standard input (la variabile in infatti è un oggetto statico proprio della classe System).
Questo canale di input, rappresentato dall’oggetto Isr, viene dotato di buffer, ossia di capacità di leggere
gruppi di caratteri o dati cumulandoli, ossia tenendone memoria.
Bfr = new BufferedReader(Isr);
Dopo aver fatto questo, questi canali di input bufferizzati, possono leggere dati multipli, senza doversi
appoggiare a cicli di lettura, ma operando in modo analogo a quello di altri linguaggi di programmazione
Read in Pascal, Input in QuickBasic, ecc. Le operazioni di questo tipo in Java vengono svolte con s1 =
Queste operazioni in Java devono avere però essere abbinate obbligatoriamente ad un
opportuno controllo di errore. Questo è visibile poco sotto. Il costrutto try… catch, che successivamente
sarà analizzato più a fondo, serve a controllare se le operazioni di input hanno avuto problemi o no, nella
lettura dei dati. La gestione di questi problemi riguarda direttamente le operazioni in quanto tali, non la
successiva gestione dei dati ed il loro uso. Il metodo readLine() legge tutto come una stringa (sequenza di
caratteri) e quindi, in quanto tale, è molto generale nel suo uso.
Successivamente il programma in questione deve convertire i dati letti in un formato meno generico, ossia
intero nel nostro caso. La conversione in questo caso risulta piuttosto complessa e laboriosa
Bfr.readLine();
x = Integer.valueOf(s1).intValue();
ovviamente x è una variabile dichiarata intera. Il valore s1 che è una stringa (dal contenuto opportuno),
viene in questo modo convertito in numero intero a tutti gli effetti. Tali conversioni possono fallire, nel caso i
dati non siano coerenti con il tipo previsto e quindi non convertibili. Nel programma in questione si suppone
un input adeguato e non è stato previsto un controllo di errore sulle conversioni.
Infine viene effettuata la somma, che non ha una sintassi particolare, né diversa da altri linguaggi:
r = x + y;
Infine si ricava il risultato tramite il solito costrutto di output che usa la classe System:
System.out.println("Il risultato e': " + r);
Da notare che, sebbene Java non effettui di regola conversioni implicitamente, in questo caso la
concatenazione di r con la stringa costante che la precede è una operazione di conversione implicita del
valore di r in stringa.