













Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Appunti università della calabria - ingegneria informatica
Tipologia: Appunti
1 / 21
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!














1
2
3
Finora abbiamo visto programmi Java che
interagiscono con l’utente soltanto tramite i flussi di
ingresso e di uscita standard
Ci chiediamo: è possibile leggere e scrivere file
all’interno di un programma Java?
Ci interessa soprattutto affrontare il problema della
gestione di file di testo (file contenenti caratteri)
esistono anche i file binari , che contengono
semplicemente configurazioni di bit che rappresentano
qualsiasi tipo di dati
La gestione dei file avviene interagendo con il
sistema operativo mediante classi del pacchetto
java.io della libreria standard
4
Il modo più semplice:
Creare un oggetto “ lettore di file ” ( FileReader );
Creare un oggetto Scanner , che già conosciamo
Collegare l’oggetto Scanner al lettore di file invece
che all’input standard
In questo modo possiamo usare i consueti metodi di
Scanner ( next , nextLine , ecc.) per leggere i dati
contenuti nel file
FileReader reader = new FileReader(“input.txt”);
Scanner in = new Scanner(reader);
Prima di leggere caratteri da un file (esistente) occorre
aprire il file in lettura
questa operazione si traduce in Java nella creazione di
un oggetto di tipo FileReader
il costruttore necessita del nome del file sotto forma di
stringa : “file.txt”
Attenzione : se il file non esiste, viene lanciata
l’eccezione FileNotFoundException a gestione
obbligatoria
FileReader reader = new FileReader("file.txt");
Con l’oggetto di tipo FileReader si può invocare il metodo
read() che restituisce un intero a ogni invocazione,
iniziando dal primo carattere del file e procedendo fino
alla fine del file stesso
Non è possibile tornare indietro e rileggere caratteri già letti
bisogna creare un nuovo oggetto di tipo FileReader
FileReader reader = new FileReader("file.txt");
while(true)
{ int x = reader.read(); // read restituisce un
if (x == -1) break; // intero che vale -
char c = (char) x; // se il file è finito
//... elaborazione di c
} // il metodo puo` lanciare IOException, da gestire!!
7
È più comodo “ avvolgere ” l'oggetto FileReader in un
oggetto di tipo Scanner
Si può leggere una riga alla volta usando il metodo
nextLine di Scanner
Quando il file finisce, il metodo hasNextLine di Scanner
restituisce un valore false
FileReader reader = new FileReader("file.txt");
Scanner in = new Scanner(reader);
while(in.hasNextLine())
{ String line = in.nextLine();
//... elaborazione della stringa
} // il costruttore FileReader lancia IOException, da gestire!!
8
Al termine della lettura del file (che non
necessariamente deve procedere fino alla fine…)
occorre chiudere il file
Il metodo close() lancia IOException , da gestire
obbligatoriamente
Se il file non viene chiuso non si ha un errore, ma una
potenziale situazione di instabilità per il sistema
operativo
FileReader reader = new FileReader("file.txt");
...
reader.close();
9
Il modo più semplice:
Creare un oggetto “scrittore” PrintWriter
Collegare l’oggetto PrintWriter ad un file
In questo modo possiamo usare i metodi print , println ,
ecc. per leggere i dati contenuti nel file
Attenzione : se output.txt non esiste viene creato. Ma
se esiste già viene svuotato prima di essere scritto
E se vogliamo aggiungere in coda al file senza
cancellare il testo gia’ contenuto?
PrintWriter out = new PrintWriter(“output.txt”);
FileWriter writer = new FileWriter("file.txt“, true);
PrintWriter out = new PrintWriter(writer);
boolean append
10
Attenzione : bisogna sempre chiudere un oggetto
PrintWriter dopo avere terminato di usarlo
Anche questo metodo lancia IOException , da gestire
obbligatoriamente
Se non viene invocato non si ha un errore, ma è
possibile che la scrittura del file non venga ultimata
prima della terminazione del programma, lasciando il
file incompleto
PrintWriter out = new PrintWriter(“output.txt”);
...
out.close();
Molti problemi di elaborazione richiedono la lettura
di una sequenza di dati in ingresso
ad esempio, calcolare la somma di numeri in virgola
mobile, ogni numero inserito su una riga diversa
Altrettanto spesso il programmatore non sa quanti
saranno i dati forniti in ingresso dall’utente
Nuovo Problema : leggere una sequenza di dati in
ingresso finché i dati non sono finiti
In particolare questo succede quando leggiamo dati da
un file
Possibile soluzione :
Scanner possiede i metodi hasNext , hasNextLine ,
ecc., che restituiscono false se l’input è terminato
FileReader reader = new FileReader(“input.txt”);
Scanner in = new Scanner(reader);
// ma anche Scanner in = new Scanner(System.in);
while (in.hasNextLine())
{
String line = in.nextLine();
... // elabora line
}
Usiamo il metodo predicativo hasNextLine come
condizione di uscita dal ciclo di input
19
Scomposizione di stringhe in “token”
redirezione, piping
Il flusso di errore standard
20
21
Tutti gli esempi visti fino ad ora prevedevano
l’inserimento dei dati in ingresso uno per riga , ma
spesso è più comodo o più naturale per l’utente
inserire più dati per riga
ad esempio, cognome dello studente e voto
Dato che nextLine legge un’intera riga, bisogna
imparare ad estrarre le sottostringhe relative ai singoli
dati che compongono la riga
non si può usare substring , perché in generale non
sono note la lunghezza e la posizione di inizio dei singoli
dati nella riga
22
Per la scomposizione di stringhe in sottostringhe
delimitate da spazi, è di nuovo molto utile la classe
Scanner
una sottostringa con caratteristiche sintattiche ben
definite (ad esempio, delimitata da spazi…) si chiama
token
Scanner considera come delimitatori di sottostringhe gli
spazi, i caratteri da tabulazione e i caratteri di “andata a
capo”
Per scomporre una stringa in token usando Scanner ,
innanzitutto bisogna creare un oggetto della classe
fornendo la stringa come parametro al costruttore
Successive invocazioni del metodo next restituiscono
successive sottostringhe, fin quando l’invocazione di
hasNext restituisce true
Scanner in = new Scanner(System.in);
String line = in.nextLine();
Scanner t = new Scanner(line);
while (t.hasNext())
{ String token = t.next();
// elabora token
}
import java.util.Scanner;
public class WordCounter
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int count = 0;
boolean done = false;
while (in.hasNextLine())
{
String line = in.nextLine();
Scanner t = new Scanner(line);
while (t.hasNext())
{
t.next(); // non devo elaborare
count++;
}
}
System.out.println(count + " parole");
}
}
25
Principali classi e metodi utilizzabili
Scanner e nextLine() per leggere intere righe di input
Scanner e next per scomporre le righe in parole
Integer.parseInt() e Double.parseDouble() per
convertire stringhe in numeri
Situazioni da gestire
Terminazione di input : metodo hasNextLine() di
Scanner , e/o uso di caratteri sentinella (ad es. Q)
IOException (da gestire obbligatoriamente ) se
lavoriamo con file
NumberFormatException (gestione opzionale) lanciate
da Integer.parseInt() e Double.parseDouble()
26
27
Usando i programmi scritti finora si inseriscono dei dati
da tastiera, che al termine non vengono memorizzati
per elaborare una serie di stringhe bisogna inserirle
tutte, ma non ne rimane traccia!
Una soluzione “logica” sarebbe che il programma
leggesse le stringhe da un file
questo si può fare con il reindirizzamento dell’input
standard , consentito da quasi tutti i sistemi operativi
28
Il reindirizzamento dell’input standard, sia in sistemi Unix
che nei sistemi MS Windows, si indica con il carattere <
seguito dal nome del file da cui ricevere l’input
Il file testo.txt viene collegato all’input standard
Il programma non ha bisogno di alcuna istruzione
particolare, semplicemente System.in non sarà più
collegato alla tastiera ma al file specificato
java Pappagaller < testo.txt
//classe che ripete a pappagallo l'input inserito, un token a riga
import java.util.Scanner;
public class Pappagaller
{ public static void main(String[] args)
{ Scanner in = new Scanner(System.in);
while(in.hasNext())
System.out.println(in.next());
}
}
A volte è comodo anche il reindirizzamento dell’ output
ad esempio, quando il programma produce molte righe
di output, che altrimenti scorrono velocemente sullo
schermo senza poter essere lette
I due reindirizzamenti possono anche essere
combinati
java Pappagaller > output.txt
java Pappagaller < testo.txt > output.txt
Supponiamo di dovere ulteriormente elaborare l'output
prodotto da un programma
Ad esempio, una elaborazione molto comune consiste
nell’ ordinare le parole
questa elaborazione è cosi` comune che moltii sistemi
operativi hanno un programma sort , che riceve da standard
input un insieme di stringhe (una per riga) e le stampa a
standard output ordinate lessicograficamente (una per riga)
Per ottenere le parole di testo.txt una per riga e ordinate,
abbiamo bisogno di un file temporaneo (ad es. temp.txt )
che serve solo a memorizzare il risultato intermedio ,
prodotto dal primo programma e utilizzato dal secondo
java Pappagaller < testo.txt > temp.txt
sort < temp.txt > testoOrdinato.txt
37 38
39
Per ricevere informazione dall’esterno un programma
Apre un flusso su una sorgente di informazione (che può
essere un file, la memoria, l’input standard…)
Legge l’informazione in maniera sequenziale
Per spedire informazione verso l’esterno un programma
Apre un flusso su una destinazione (che può essere un
file, la memoria, l’output standard…)
Scrive l’informazione in maniera sequenziale
40
Java gestisce l’input usando due categorie di oggetti
Ovvero due distinte gerarchie di classi
Flussi di input/output
Le classi astratte InputStream , OutputStream e le loro
sottoclassi gestiscono sequenze di byte (formato binario)
Lettori e scrittori
Le classi astratte Reader , Writer , e le loro sottoclassi
gestiscono sequenze di caratteri (formato testo)
È possibile trasformare
un flusso di input in un
lettore
E un flusso di output in
uno scrittore
Formato testo :
I dati sono rappresentati come sequenze di caratteri
Formato binario :
I dati sono rappresentati come sequenze di byte
Esempio : il numero intero 12345
In formato testo viene memorizzato come sequenza dei
cinque caratteri ‘1’ ‘2’ ‘3’ ‘4’ ‘5’
In formato binario viene memorizzato come sequenze
dei quattro byte 0 0 48 57
13
12
5
4
3
= (
5
4 ) x 2
8
5
4
3
0 ) = 48 x 256 + 57
Tutti i flussi di input hanno metodi read (per leggere
un singolo byte ) e close (per rilasciare le risorse)
Tutti i flussi di output hanno metodi write (per scrivere
un singolo byte ) e close (per rilasciare le risorse)
43
Tutti i lettori hanno metodi read (per leggere un
singolo char ) e close (per rilasciare le risorse)
Tutti gli scrittori hanno metodi write (per scrivere un
singolo char ) e close (per rilasciare le risorse)
44
Per usare l'oggetto System.in (di tipo InputStream),
senza ricorrere a Scanner , dobbiamo risolvere tre
problemi
System.in consente di leggere byte , mentre noi
abbiamo bisogno di leggere caratteri e righe di input
BufferedReader e invocando il suo metodo readLine
se il metodo readLine trova un errore durante la lettura
dell’input, genera una eccezione
il metodo readLine restituisce sempre una stringa
45
Per trasformare un flusso di input in un lettore di
caratteri si usa la classe InputStreamReader
Oggetti di tipo InputStreamReader leggono caratteri
La classe ha solo il metodo read che legge un carattere
alla volta (e restituisce 1 se l’input è terminato)
Noi vogliamo leggere un’intera riga di input, fino al
carattere Invio
Questo si può fare , leggendo un carattere alla volta e
poi componendo la stringa totale, ma è scomodo
InputStreamReader reader =
new InputStreamReader(System.in);
46
La classe BufferedReader trasforma un lettore a
caratteri singoli in un lettore con buffer
(“bufferizzato”), che può leggere una riga per volta
Si dice che l’oggetto di tipo BufferedReader avvolge
l’oggetto di tipo InputStreamReader (wrapping)
BufferedReader ha un comodo metodo readLine
readLine restituisce null se i dati in ingresso sono
terminati
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(reader);
System.out.println("Inserire il nome");
String firstName = buffer.readLine();
Riassumendo:
L’oggetto di tipo InputStreamReader viene utilizzato
soltanto per costruire l’oggetto di tipo
BufferedReader , quindi può venire passato
direttamente senza memorizzarlo in una variabile
BufferedReader buffer = new BufferedReader(
new InputStreamReader(System.in));
System.out.println("Inserire il nome");
String firstName = buffer.readLine();
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class MakePassword
{ public static void main(String[] args)
{ try {
BufferedReader c = new BufferedReader(
new InputStreamReader(System.in));
System.out.println("Inserire il nome");
String firstName = c.readLine();
System.out.println("Inserire il cognome");
String lastName = c.readLine();
System.out.println("Inserire l’età");
int age = Integer.parseInt(c.readLine());
//(continua)
55
Prima di scrivere caratteri in un file occorre aprire il
file in scrittura
questa operazione si traduce in Java nella creazione
di un oggetto di tipo FileWriter
il costruttore necessita del nome del file sotto forma di
stringa e può lanciare l’eccezione IOException , che
deve essere gestita
sovrascritto con i nuovi contenuti
FileWriter writer = new FileWriter("file.txt");
56
L’oggetto di tipo FileWriter non ha i comodi metodi
print / println
è utile creare un oggetto di tipo PrintWriter che
avvolge l’esemplare di FileWriter , aggiungendo la
possibilità di invocare print / println con qualsiasi
argomento
FileWriter writer = new FileWriter("file.txt");
PrintWriter pw = new PrintWriter(writer);
pw.println("Ciao");
...
57
Al termine della scrittura del file occorre chiudere il file
Anche questo metodo lancia IOException , da gestire
obbligatoriamente
Se non viene invocato non si ha un errore, ma è possibile
che la scrittura del file non venga ultimata prima della
terminazione del programma, lasciando il file incompleto
FileWriter writer = new FileWriter("file.txt");
...
writer.close();
58
Nota: la classe ArrayList trattata nel capitolo 8 del libro di testo non
fa parte del nostro programma
Scrivere un programma che
legge dallo standard input una sequenza di dieci
numeri in virgola mobile, uno per riga
chiede all’utente un numero intero index e visualizza il
numero che nella sequenza occupava la posizione
indicata da index
Occorre memorizzare tutti i valori della sequenza
Potremmo usare dieci variabili diverse per
memorizzare i valori, selezionati poi con una lunga
sequenza di alternative, ma se i valori dovessero
essere mille?
61
Lo strumento messo a disposizione dal linguaggio
Java per memorizzare una sequenza di dati si chiama
array (che significa “sequenza ordinata”)
la struttura array esiste in quasi tutti i linguaggi di
programmazione
Un array in Java è un oggetto che realizza una
raccolta di dati che siano tutti dello stesso tipo
Potremo avere quindi array di numeri interi, array di
numeri in virgola mobile, array di stringhe, array di
conti bancari...
62
Come ogni oggetto , un array deve essere costruito
con l’operatore new , dichiarando il tipo di dati che
potrà contenere
Il tipo di dati di un array può essere qualsiasi tipo di
dati valido in Java
uno dei tipi di dati fondamentali o una classe
e nella costruzione deve essere seguito da una
coppia di parentesi quadre che contiene la
dimensione dell’array, cioè il numero di elementi
che potrà contenere
new double[10];
63
Come succede con la costruzione di ogni oggetto,
l’operatore new restituisce un riferimento all’array
appena creato, che può essere memorizzato in una
variabile oggetto dello stesso tipo
Attenzione : nella definizione della variabile oggetto
devono essere presenti le parentesi quadre, ma non
deve essere indicata la dimensione dell’array; la
variabile potrà riferirsi solo ad array di quel tipo, ma di
qualunque dimensione
double[] values = new double[10];
// si può fare in due passi
double[] values;
values = new double[10];
64
Al momento della costruzione, tutti gli elementi
dell’array vengono inizializzati ad un valore,
seguendo le stesse regole viste per le variabili di
esemplare
Per accedere ad un elemento dell’array si usa
La stessa sintassi si usa per modificare un
elemento dell’array
double[] values = new double[10];
double oneValue = values[3];
double[] values = new double[10];
values[5] = 3.4;
Il numero utilizzato per accedere ad un particolare
elemento dell’array si chiama indice
L’indice può assumere un valore compreso tra 0
( incluso ) e la dimensione dell’array ( esclusa ), cioè
segue le stesse convenzioni viste per le posizioni dei
caratteri in una stringa
il primo elemento ha indice 0
l’ultimo elemento ha indice ( dimensione 1)
double[] values = new double[10];
double oneValue = values[ 3 ];
values[ 5 ] = 3.4;
L’indice di un elemento di un array può, in generale,
essere un’espressione con valore intero
Cosa succede se si accede ad un elemento dell’array
con un indice sbagliato (maggiore o uguale alla
dimensione, o negativo)?
l’ambiente di esecuzione genera un’eccezione di tipo
ArrayIndexOutOfBoundsException
double[] values = new double[10];
int a = 4 ;
values[a + 2 ] = 3.2; // modifica il
// settimo elemento
73
Uno degli errori più comuni con gli array è l’utilizzo di
un indice che non rispetta i vincoli
il caso più comune è l’uso di un indice uguale alla
dimensione dell’array, che è il primo indice non valido…
Come abbiamo visto, l’ambiente runtime (cioè
l’interprete Java) segnala questo errore con
un’eccezione che arresta il programma
double[] values = new double[10];
values[10] = 2; // ERRORE IN ESECUZIONE
74
Quando si assegnano i valori agli elementi di un
array si può procedere così
ma se si conoscono tutti gli elementi da inserire si
può usare questa sintassi ( migliore )
oppure ( accettabile, ma meno chiara )
int[] primes = new int[3];
primes[0] = 2;
primes[1] = 3;
primes[2] = 5;
int[] primes = { 2, 3, 5};
int[] primes = new int[] { 2, 3, 5};
75
public static double sum(double[] values)
{ if (values == null)
throw new IllegalArgumentException();
if (values.length == 0)
return 0;
double sum = 0;
for (int i = 0; i < values.length; i++)
sum = sum + values[i];
return sum;
}
76
public static int[] resize(int[] oldArray, int newLength)
{ if (newLength < 0 || oldArray == null)
throw new IllegalArgumentException();
int[] newArray = new int[newLength];
int count = oldArray.length;
if (newLength < count)
count = newLength;
for (int i = 0; i < count; i++)
newArray[i] = oldArray[i];
return newArray;
}
Un metodo può anche usare un array come valore
di ritorno
Questo metodo restituisce un array contenente i dati
dell’array oldArray e con lunghezza newLength
int[] values = {1, 7, 4};
values = resize(values, 5);
values[4] = 9;
double[] data = new double[10]
for (int i = 0; i < data.length; i++)
data[i] = i * i;
79
Ricordando che una variabile che si riferisce ad un
array è una variabile oggetto
contiene un riferimento all’oggetto array
copiando il contenuto della variabile in un’altra non
si copia l’array , ma si ottiene un altro riferimento
allo stesso oggetto array
double[] x = new double[6];
double[] y = x;
x y
80
Se si vuole ottenere una copia dell’array , bisogna
creare un nuovo array dello stesso tipo e con la
stessa dimensione
copiare ogni elemento del primo array nel
corrispondente elemento del secondo array
double[] values = new double[10];
// inseriamo i dati nell’array
...
double[] otherValues = new double[values.length];
for (int i = 0; i < values.length; i++)
otherValues[i] = values[i];
81
Invece di usare un ciclo, è possibile (e più efficiente )
invocare il metodo statico arraycopy della classe
System (nel pacchetto java.lang )
Il metodo System.arraycopy consente di copiare un
porzione di un array in un altro array (grande almeno
quanto la porzione che si vuol copiare)
double[] values = new double[10];
// inseriamo i dati nell’array
...
double[] otherValues = new double[values.length];
System.arraycopy(values, 0, otherValues, 0,
values.length);
82
from to
fromStart
toStart
count
System.arraycopy(from,fromStart,to,toStart,count);
È anche possibile usare il metodo clone
Attenzione : il metodo clone restituisce un
riferimento di tipo Object
È necessario effettuare un cast per ottenere un
riferimento del tipo desiderato
double[] otherValues = (double[]) values.clone();
91
Restituisce un array di lunghezza newLength e
contenente i dati dell’array oldArray
Crea un nuovo array più grande di quello “pieno” e
copia in esso il contenuto del vecchio array
Useremo questo metodo molto spesso!
public static int[] resize(int[] oldArray, int newLength)
{ if (newLength < 0 || oldArray == null)
throw new IllegalArgumentException();
int[] newArray = new int[newLength];
int count = oldArray.length;
if (newLength < count)
count = newLength;
for (int i = 0; i < count; i++)
newArray[i] = oldArray[i];
return newArray;
}
int[] values = {1, 3, 7};
values = resize(values, 5);
92
93
Costruiremo una classe ArrayAlgs
Sarà una “ classe di utilità ” (come la classe Math ) che
contiene una collezione di metodi statici che
realizzano algoritmi per l’elaborazione di array
public class ArrayAlgs
{ ...
public static int[] resize(int[] oldArray, int newLength)
{ ... }
public static ...
} //in un'altra classe i metodi verranno invocati cosi`
v = ArrayAlgs.resize(v,2*v.length);
94
La classe Math ha il metodo random( ) per generare
sequenze di numeri pseudo casuali
Una invocazione del metodo restituisce un numero reale
pseudo casuale nell’intervallo [0, 1)
Per ottenere numeri interi casuali nell’intervallo [a, b] ...
Usando random scriviamo nella classe ArrayAlgs un
metodo che genera array di numeri interi casuali
public static int[] randomIntArray(int length, int n)
{
int[] a = new int[length];
for (int i = 0; i < a.length; i++)
// a[i] e` un num intero casuale tra 0 e n-1 inclusi
a[i] = (int) (n * Math.random());
return a;
}
double x =Math.random();
int n = (int)(a + (1+b-a)*Math.random());
Se cerchiamo di stampare un array sullo standard output
non riusciamo a visualizzarne il contenuto ...
Scriviamo nella classe ArrayAlgs un metodo che crea
una stringa contenente gli elementi di un array
public static String printArray(int[] v, int vSize)
{ String s = "[";
for (int i = 0; i 97
Primo algoritmo : se l’ordine tra gli elementi dell’array
non è importante (cioè se l’array realizza il concetto
astratto di insieme), è sufficiente
copiare l’ultimo elemento dell’array nella posizione
dell’elemento da eliminare
ridimensionare l’array (oppure usare la tecnica degli
array riempiti soltanto in parte)
public static void remove(int[] v, int vSize, int index)
{
v[index] = v[vSize - 1];
}
int[] a = {1,2,3,4,5};
int aSize = a.length;
ArrayAlgs.remove(a,aSize,1);
aSize--; a diventa [1,5,3,4]
98
Secondo algoritmo se l’ordine tra gli elementi
dell’array deve essere mantenuto allora l'algoritmo è
più complesso. Bisogna
Spostare tutti gli elementi dell’array successivi
all'elemento da rimuovere nella posizione con indice
immediatamente inferiore
ridimensionare l’array (oppure usare la tecnica degli
array riempiti soltanto in parte)
public static void removeSorted(int[] v, int vSize, int index)
{ for (int i=index; i index; i--)
v[i] = v[i - 1];
v[index] = value;
return v;
}
int[] a = {1,2,3,4,5};
int aSize = a.length;
a = ArrayAlgs.insert(a,aSize,2,7);
aSize++;
a diventa [1,2,7,3,4,5]
index
i trasferimenti vanno
eseguiti dal basso in alto!
Algoritmo : la strategia più semplice è chiamata
ricerca lineare. Bisogna
scorrere gli elementi dell’array finchè l'elemento cercato
non viene trovato oppure si raggiunge la fine dell'array
Nel caso in cui il valore cercato compaia più volte, questo
algoritmo trova soltanto la prima occorrenza del valore e
non le successive
public static int linearSearch(int[] v, int vSize, int value)
{
for (int i = 0; i < vSize; i++)
if (v[i] == value) return i; // trovato valore
return -1; // valore non trovato
}
int[] a = {1,2,3,4,5};
int aSize = a.length;
int i = ArrayAlgs.linearSearch(a,aSize,4);
i vale 3
109
Ciascun indice deve essere
intero
maggiore o uguale a 0
minore della dimensione corrispondente
Per conoscere il valore delle due dimensioni
il numero di righe è
il numero di colonne è
(perché un array bidimensionale è in realtà un array di
array e ogni array rappresenta una riga…)
powers.length;
powers[0].length;
110
import java.util.Scanner;
/**
Programma che visualizza una tabella con i valori
delle potenze "x alla y", con x e y che variano
indipendentemente tra 1 ed un valore massimo
assegnato dall’utente.
I dati relativi a ciascun valore di x compaiono
su una riga, con y crescente da sinistra
a destra e x crescente dall’alto in basso.
*/
public class TableOfPowers
{ public static void main(String[] args)
{ Scanner in = new Scanner(System.in);
System.out.println(
"Calcolo dei valori di x alla y");
System.out.println("Valore massimo di x:");
int maxX = in.nextInt();
System.out.println("Valore massimo di y:");
int maxY = in.nextInt();
int maxValue =
(int) Math.round(Math.pow(maxX, maxY));
int columnWidth =
1 + Integer.toString(maxValue).length();
int[][] powers = generatePowers(maxX, maxY);
printPowers(powers, columnWidth);
}
// continua
111
//continua
/**
Genera un array bidimensionale con i
valori delle potenze di x alla y.
*/
private static int[][] generatePowers(int x,
int y)
{ int[][] powers = new int[x][y];
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
powers[i][j] =
(int)Math.round(Math.pow(i + 1, j + 1));
return powers;
}
//continua
Notare l’utilizzo di metodi private per la
scomposizione di un problema in sottoproblemi più
semplici
perché il metodo viene invocato da chi l’ha scritto
112
//continua
/**
Visualizza un array bidimensionale di
numeri interi con colonne di larghezza
fissa e valori allineati a destra.
*/
private static void printPowers(int[][] v,
int width)
{ for (int i = 0; i < v.length; i++)
{ for (int j = 0; j < v[i].length; j++)
{ String s = Integer.toString(v[i][j]);
while (s.length() < width)
s = " " + s;
System.out.print(s);
}
System.out.println();
}
}
}
Quando si esegue un programma Java, è possibile
fornire dei parametri dopo il nome della classe che
contiene il metodo main
Tali parametri vengono letti dall’interprete Java e
trasformati in un array di stringhe che costituisce il
parametro del metodo main
java Program 2 33 Hello
public class Program {
public static void main(String[] args) {
System.out.println(args.length);
System.out.println(args[1]);
}
}
3
33
115
Uso tipico degli argomenti sulla riga di comandi
Specificare opzioni e nomi di file da leggere/scrivere
Per convenzione le stringhe che iniziano con un
trattino sono considerate opzioni
java LineNumberer –c HelloWorld.java HelloWorld.txt
for (int i = 0; i< args.length; i++)
{ String a = args[i];
if (a.startsWith(“-”)) // è un’opzione
{
if (a.equals(“-c”)) useCommentDelimiters = true;
}
else if (inputFileName == null) inputFileName = a;
else if (outputFileName == null) outputFileName = a;
}
116
117
Scriviamo un programma che riceve in ingresso un
elenco di dati che rappresentano
i cognomi di un insieme di studenti
il voto della prova scritta
il voto della prova orale
I dati di uno studente vengono inseriti in una riga
separati da uno spazio
prima il cognome, poi il voto scritto, poi il voto orale
I dati sono terminati da una riga vuota
118
Ora aggiungiamo le seguenti funzionalità
il programma chiede all’utente di inserire un comando
per identificare l’elaborazione da svolgere
studente ”
Nel caso S il programma
dei suoi voti
import java.util.StringTokenizer;
import java.util.Scanner;
public class StudentManager
{ public static void main(String[] args)
{ Scanner in = new Scanner(System.in);
String[] names = new String[10];
double[] wMarks = new double[10];
double[] oMarks = new double[10];
int count = 0; // array riempiti solo in parte
boolean done = false;
while (!done)
{ String input = in.nextLine();
if (input.length() == 0) done=true;
else
{
StringTokenizer t = new StringTokenizer(input);
if (count == names.length)
{ names = resizeString(names, count * 2);
wMarks = resizeDouble(wMarks, count * 2);
oMarks = resizeDouble(oMarks, count * 2);
}
names[count] = t.nextToken();
wMarks[count] = Double.parseDouble(t.nextToken());
oMarks[count] = Double.parseDouble(t.nextToken());
count++;
}
}
//continua
done = false; //continua
while (!done)
{
System.out.println("Comando? (Q per uscire, S per vedere)");
String command = in.nextLine();
if (command.equalsIgnoreCase("Q"))
done = true;
else if (command.equalsIgnoreCase("S"))
{
System.out.println("Cognome?");
String name = in.nextLine();
printAverage(names, wMarks, oMarks,name, count); //NOTA:
//non abbiamo gestito l'eccezione lanciata da printAverage
}
else
{ System.out.println("Comando errato");
}
}
}
private static void printAverage(String[] names, double[] wMarks,
double[] oMarks, String name, int count)
{ int i = findName(names, name, count);
if (i == -1) throw new IllegalArgumentException();
else
{ double avg = (wMarks[i] + oMarks[i]) / 2;
System.out.println(name + " " + avg);
}
} //continua