edutecnica
 


Struttura di un programma in Java

La sintassi generale usata per scrivere un programma in linguaggio Java, anche soltanto in modo procedurale cioè senza l'uso di oggetti istanziati, può essere schematizzato con la seguente sintassi: .

public class nomeclasse {
public static void main (String args[]) {
[istruzioni]
}//fine main
// altri eventuali metodi (funzioni o sottoprogrammi)
}// fine class


In un'applicazione console, il metodo main() deve sempre essere presente e dichiara il punto in cui inizia l'esecuzione del programma. Questa formulazione (orientata agli oggetti) rappresenta un passaggio obbligato anche se si volessero eseguire semplici programmi facilmente scrivibili in linguaggi sequenziali (anche se strutturati) come il C o il Pascal.

Prendiamo ad esempio il seguente listato Pascal
program sum;
var
      x,y,somma:integer;
begin
     write('ins. x:');
     readln(x);
     write('ins. y:');
     readln(y);
     somma:=x+y;
     writeln(somma);
end.

Esegue delle semplici operazioni di I/O: accetta due interi da tastiera (x e y) e ne restituisce la somma. Riportato in Java potremo scrivere:
import java.io.*;
class sum {
public static void main (String[] args) throws IOException {
     int x,y,somma;
     InputStreamReader input=new InputStreamReader(System.in);
     BufferedReader h= new BufferedReader(input);
     System.out.print("ins.x:");
     x=Integer.parseInt(h.readLine().trim());
     System.out.print("ins.y:");
     y=Integer.parseInt(h.readLine().trim());
     somma=x+y;
     System.out.println(somma);
}//fine main
} //fine class

In prima battuta non si può certo dire che il linguaggio Java abbia introdotto delle semplificazioni: qualche chiarimento è obbligatorio.
import java.io.*;
ha lo scopo di dichiarare che nella classe vengono usate classi provenienti dal package (libreria) java.io; nel nostro caso, le classi importate sono:
BufferedReader
InputStreamReader
IOException

Si nota poi l'aggiunta del comando throws nella riga:
main (String[] args) throws IOException
che è una richiesta di 'sollevare' il programmatore dalla responsabilità di eventuali eccezioni nelle operazioni di I/O.

La complicazione principale è data dal fatto che in Java i dati acquisiti da tastiera, sono considerati per definizione delle stringhe; tramite i comandi:
InputStreamReader input=new InputStreamReader(System.in);
BufferedReader h= new BufferedReader(input);

Viene definito l'oggetto h che effettivamente legge delle stringhe da tastiera, ma con delle stringhe in input è piuttosto difficile eseguire delle operazioni ponderali di somma, per cui l'istruzione:
y=Integer.parseInt(h.readLine().trim());
acquisisce i dati in ingresso e li converte in tipi di dato intero. La conversione avviene tramite la funzione Integer.parseInt(), mentre la funzione trim() toglie eventuali spazi in testa e in coda alla stringa da convertire.
Quello che possiamo dire è che tramite questo modello possiamo tradurre in Java tutti gli algoritmi già elaborati in linguaggio C.

Identificatori

Nella stesura del codice ci si ritrova a dover assegnare dei nomi (alle costanti, alle variabili a dei metodi) detti identificatori, questi nomi possono essere assegnati arbitrariamente, ma bisogna ricordarsi di evitare le seguenti parole riservate:

abstract boolean break byte case catch
char class const continue default do
double else extends false final finally
float for goto if implements import
inatanceof int interface long native new
null package private protected public return
short static super switch synchronized this
throw throws transient true try void
volatile while        

Un identificatore non può dunque essere una parola riservata, deve incominciare con una lettera (a-z o A-Z) o con _ (underscore) può contenere lettere, cifre, _, a piacere

Variabili

Una variabile è un'associazione fra un identificatore e un valore; è una "scatola" che contiene un valore. In Java ogni variabile è associata ad un tipo di dati. Un tipo è quindi un insieme di valori e di operazioni eseguibili su quei valori. Prima di usare una variabile bisogna, quindi, dichiarare il suo tipo. Di solito questo viene fatto nella parte dichiarativa di un programma. La dichiarazione di una variabile si esprime con la sintassi:
Tipo nomeVariabile
sono dichiarazioni di variabili
int base, altezza; //dichiara le variabili intere base e altezza senza inizializzarle
float peri, area=3.67; //dichiara le variabili float peri e area inizializzando solo quest'ultima
char ch='A';//dichiarazione ed inizializzazione di variabile char
boolean a=false,b;//dichiara due boolean, inizializza solo a
int[] T;//dichiara un vettore di interi
String[] s;//dichiara un vettore di stringhe

Come in C per cambiare il contenuto di una variabile si usa un'istruzione di assegnamento:

nomeVariabile=espressione;

Lifetime delle variabili

Per quello che riguarda il tempo di vita e il campo di azione di una variabile, valgono le seguenti regole:
Una variabile locale cessa di esistere all'uscita del blocco in cui è stata dichiarata. Una variabile locale è visibile dal punto in cui viene dichiarata, fino alla fine del suo blocco.

ad esempio nel codice:
{int a=2, b=3;
     {int x=a
          a=b;
          b=x;
     }
System.out.println(a);
System.out.println(x);//dà errore :è fuori dal suo campo di azione
}

Costanti

La dichiarazione di costanti assume invece la seguente sintassi:

final int n=5;
final float prz=11.50;
final String messaggio="ciao";


L'uso del modificatore final è obbligatorio.
Il modificatore final, trasforma una variabile in una costante, visibile nel blocco della classe.
La tipica applicazione di test 'ciao a tutti' verrebbe codificata:

import java.io.*;
class ciao {
public static void main (String[] args) throws IOException {
     final String MSG = "Ciao ";
     InputStreamReader in=new InputStreamReader(System.in);
     BufferedReader h= new BufferedReader(in);
     String s;
     s=h.readLine();
     System.out.println(MSG+s);
}//fine main
}//fine class


Come è possibile riconoscere, Java mantiene la stessa sintassi del linguaggio C; in particolare è obbligatorio rispettare la regola del punto e virgola: cioè, ogni istruzione deve essere seguita (terminata) da un punto e virgola. Come nel caso del C, il linguaggio è case sensitive, ciò vuol dire che la variabile Pippo è considerata differente da una variabile dichiarata pippo.

Tipi di dati (primitivi)

boolean 1bit false/true
byte 1byte da -128 a 127
short 2byte da -32768 a 32767
int 4byte da -231 a 231-1
long 8byte da -263 a 263-1
char 2byte da \u0000 (0) a \uFFFF (65535)
float 4byte ±3.40282347·10+38 a ±1.40239846·10-45
double 8byte da±1.7976931348623157·10+308 a ±4.94065645841246544·10-324


Nonostante non vi sia il tipo primitivo string (ma solo la classe String) Java permette di avere letterali stringhe, che vengono racchiusi fra doppi apici, come "Ciao " già visto nel programma precedente.

Espressioni

Variabili, letterali e costanti possono essere combinate, usando opportuni operatori e rispettando alcune regole, per formare espressioni analoghe alle espressioni algebriche. Gli operatori hanno differenti priorità, o precedenze, secondo le normali consuetudini dell'algebra ad es. in a*b-c la moltiplicazione viene effettuata prima dell'addizione. Le parentesi permettono di cambiare l'ordine di esecuzione delle operazioni. Dobbiamo come al solito ricordare che se in un'espressione sono coinvolti tipi di dati differenti, il risultato sarà dello stesso tipo del dato che che occupa maggior spazio in memoria. Ad es.

int a=3,c=7;
double b=2.50;
System.out.println(a+b);
System.out.println(c/a);

fornisce in uscita
5.5
2


questo perché in a+b il dato di maggior occupazione in memoria è double , il risultato in tal caso è di tipo double; mentre in c/a il dato di maggior occupazione in memoria è sempre int, il risultato in tal caso è di tipo int. Si raccomanda in tal caso la conversione di cast :

System.out.println((double)c/a);

per evitare la perdita dei decimali.

Operatori aritmetici, logici e relazionali

Gli operatori aritmetici servono appunto ad eseguire operazioni matematiche:

operatore azione
- sottrazione
+ addizione
* moltiplicazione
/ divisione
% resto della divisione fra interi
-- decremento
++ incremento

Gli operatori relazionali, intervengono nelle espressioni logiche che implicano, prevalentemente, dati di tipo numerico.
Ovviamente restituiscono un dato booleano (true/false). Ad es.

class operatori {
public static void main (String[] args) {
     int x,y;
     boolean p,q;
     x=10;
     y=10;
     p=(x==y);
     q=(x!=y);
     System.out.println("p:"+p+"\t"+"q:"+q);
}//fine main
}//fine class


restituisce:
p:true           q:false
dato che la condizione logica p è vera, q è falsa.

Gli operatori relazionali sono i seguenti:

operatore azione
> maggiore
>= maggiore o uguale
< minore
<= minore o uguale
== uguale a
!= diverso da

Uno degli errori più ricorrenti è quello di usare l'operatore di assegnamento '=' al posto di '==' nelle espressioni condizionali.

Gli operatori logici sono coinvolti nelle associazioni fra le relazioni

operatore azione
&& and
|| or
! not

Ad. esempio

class logici {
public static void main (String[] args) {
     int x=12;
     boolean dueCifre=((x>=10)&&(x<=100));
     boolean multiploDi6=((x%6)==0);
     boolean dispari=!((x%6)==0);
     System.out.println("dueCifre:"+dueCifre);
     System.out.println("multiploDi6:"+multiploDi6);
     System.out.println("dispari:"+dispari);
}//fine main
}//fine class

restituisce
dueCifre:true
multiploDi6:true
dispari:false

come ci si poteva aspettare.

Funzioni matematiche

Ricordiamo che l'eventuale uso delle funzioni matematiche, implica la restituzione da parte di alcune di queste di numeri in virgola mobile:

operatore azione
E costante numero di Neper=2.717..
PI costante pi greco=3.14..
abs(x) valore assoluto di x
max(x,y) massimo fra due numeri
min(x,y) minimo fra due numeri
sin(x),cos(x),tan(x) funzioni trigonometriche
asin(x),acos(x),atan(x) funzioni trigonometriche inverse
ceil(x) il più piccolo intero maggiore o uguale a x
floor(x) il più grande intero minore o uguale a x
rint(x) arrotondamento di un double verso un intero
round(x) arrotondamento di un float verso un intero
exp(x) e elevato alla x
pow(x,y) x elevato alla y
log(x) logaritmo in base e di x
sqrt(x) radice quadrata di x
toDegrees(x) conversione da radianti a gradi
toRadians conversione da gradi a radianti
random() genera un random di tipo double tra 0.0 e 1.0

un esempio del loro uso:

import java.lang.Math;
class potenza {
public static void main (String[] args) {
     int x=4,y=2;
     double z;
     z=Math.pow(x,y);
     System.out.println(z);
}//fine main
}//fine class


Strutture di controllo

Le strutture di controllo, specificano l'ordine di esecuzione delle istruzioni di un programma. Così come per gli operatori le strutture di controllo Java possono essere considerate identiche a quelle già viste in linguaggio C.

if-else

L'if-else è la più comune istruzione di selezione. La sua sintassi può essere espressa nel modo seguente,

if(condizione){
     istruzioni-a;
}


Nel caso che la condizione logica sia falsa, non viene intrapresa alcuna azione e il flusso del programma riprende dall'istruzione successiva all'if. Le parentesi graffe sono obbligatorie se deve essere eseguita più di una istruzione (blocco di istruzioni)


if(condizione){
     istruzioni-a;
} else{
     istruzioni-b;
}


Quindi, un'istruzione di selezione inizia con la parola chiave if, seguita da un'espressione logica (condizione) fra parentesi tonde (detta condizione dell'if), seguita a sua volta da un blocco di istruzioni e, opzionalmente dalla parola chiave else e da un'altro blocco di istruzioni.

Un esempio di uso dell'if è:

if (x >= 0) System.out.println("x e' positivo");

Se la condizione dell' if è valutata a true viene eseguita l'istruzione successiva . Se è presente anche l'else:

if (x >= 0) System.out.príntln("x e' positivo");
else System.out.println("x e' negativo");


l'istruzione dopo l'else viene eseguita se la condizione vale false. Si dice che l'istruzione che appare subito dopo la condizione è il ramo if, mentre quella che appare dopo l'else è il ramo else.

Rimane valido anche il costrutto if-else-if qui esemplificato in un programma che determina il maggiore di 4 caratteri:

import java.io.*;
class ifElseIf {
public static void main (String[] args) throws IOException {
     InputStreamReader input=new InputStreamReader(System.in);
     BufferedReader h= new BufferedReader(input);
     int a, b, c, d, max;
     a = Integer.parseInt(h.readLine().trim());
     b = Integer.parseInt(h.readLine().trim());
     c = Integer.parseInt(h.readLine().trim());
     d = Integer.parseInt(h.readLine().trim());
     if (a>b && a>c && a>d) max = a;
     else if (b>a && b>c && b>d) max = b;
     else if (c>a && c>b && c>d) max = c;
     else max = d;
     System.out.println(max);
}//fine main
} //fine class

switch

Lo stesso schema di flusso dell'istruzione if-else-if viene seguita dal costrutto switch

switch (espressione) {
     case valore_a: {istruzioni_a;} break;
     case valore_b: {istruzioni_b;} break;
     ...
     case valore_n: {istruzioni_n;} break;
     default : {istruzioni_n;} break;
} //fine switch

L'espressione che segue la parola chiave switch (che può anche essere una semplice variabile) viene valutata e il valore ottenuto (che deve essere di tipo byte, short, int , long o char) è confrontato con tutti i letterali , , ... che seguono la parola chiave case. Se sono uguali, viene eseguita la sequenza di istruzioni corrispondente; se dopo tali istruzioni vi è la parola chiave break, il controllo passa all'istruzione successiva allo switch. Se nessun letterale è uguale al valore dell'espressione viene eseguita la sequenza di istruzioni che segue la parola chiave default .

while

Capita spesso di voler ripetere più volte le stesse istruzioni. Nei primi linguaggi di programmazione vi erano le istruzioni di salto (goto, jump); nei linguaggi di programmazione moderni le istruzioni di salto sono state sostituite dalle strutture di controllo iterative. Un ciclo while (detto anche ciclo con ripetizione precondizionale) avviene nel modo seguente: la condizione viene valutata e, se il suo valore è true, il corpo viene eseguito; poi la condizione viene valutata nuovamente e il corpo eventualmente eseguito di nuovo, e così via, finché la valutazione della condizione dà il risultato false; a questo punto viene eseguita l'istruzione successiva.

il seguente programma utilizza un ciclo while per generare casualmente un numero compreso fra 1 e 10 (inclusi), per poi stampare a video il numero. Il ciclo continuerà a funzionare finchè la condizione logica del while è vera (true).
Quando viene generato un numero maggiore o uguale a 8 la condizione diventa falsa ed il ciclo si interrompe.

Il ciclo viene eseguito almeno una volta se la variabile testata nella condizione logica è minore di 8, altrimenti, non viene eseguito nemmeno una volta.

class cicloWhile {
public static void main (String[] args) {
     int x=0;
     while(x<8){
     x=(1 + (int) (Math.random() * 10));
     System.out.println(x); }
}//fine main
}//fine class

do-while

Detto anche ciclo con ripetizione condizionale :
do{
      istruzioni;
}while(condizione);

la sequenza di istruzioni compresa tra il do e il while viene ripetuta tante volte mentre la condizione scritta dopo il while si mantiene vera; in altre parole la ripetizione termina quando la condizione diventa falsa. A differenza dei cicli for e while che verificano la condizione all'inizio del ciclo, il do-while la verifica alla fine, con la conseguenza che il do-while viene eseguito almeno sempre almeno una volta.

class cicloDoWhile{
public static void main (String[] args) {
     int x;
     do{
     //genera un numero casuale fra 1 e 10 compresi
     x=(1 + (int) (Math.random() * 10));
     System.out.println(x);
     }while(x<8);
}//fine main
}//fine class

in questo caso la variabile può anche non essere inizializzata perché entra nel ciclo almeno una volta e lì viene impostata.

for

Il costrutto for viene usato per eseguire un numero finito di cicli, la sua sintassi è:

for (inizializzazione; condizione;incremento){
     istruzioni
}

Dopo la parola chiave for, vi sono tre elementi fra parentesi tonde (detti, da sinistra a destra: l'inizializzazione, la condizione di uscita e l'istruzione di incremento) che formano l'intestazione del for e un'istruzione (detta corpo del for), che può in generale essere composta (in tal caso è obbligatorio usare le parentesi graffe). Il significato dell'istruzione for è il seguente: l'istruzione di inizializzazione assegna un valore iniziale a una variabile, detta variabile di controllo; il corpo del for viene eseguito ripetutamente fìnché vale la condizione di uscita; e a ogni iterazione la variabile di controllo viene incrementata come indicato dall'istruzione di incremento. Ad esempio, la seguente istruzione stampa tutti i numeri da 1 a 10:

for(i=1;i<=10; i++) System.out.println(i);

Come si nota in questo caso, non vengono usate le parentesi graffe, dato che ad ogni ciclo viene usata una sola istruzione.

 




edutecnica