file Counter.java
public class Counter { int value = 0; int topValue = 5; public int increment() throws Exception { if (value >= topValue) throw (new Exception()); value ++; return value; } public int getValue() { return value; } }
throw (eccezione)
eccezione
al metodo chiamante.
file MyApplication.java
public class MyApplication { public static void main (String args[]) { Counter c1 = new Counter(); System.out.println("Counter 1 has value "+c1.getValue()); try { for (int i=1; i<10; i++) { c1.increment(); System.out.println("Counter 1 is now "+c1.getValue()); } } catch (Exception e) { System.out.println("I just caught the Exception"); } } }
increment
di
Counter non sono racchiuse in un blocco try
, il compilatore
si rifiuta di compilare la classe.
catch
deve
essere dello stesso tipo che viene lanciato dal metodo chiamato.
catch()
viene eseguito se si verifica l'errore
e puo' usare i metodi e le variabili dell'oggetto eccezione per dare
un opportuno messaggio di errore.
try {istruzioni che possono causare errore } } catch (Exception e) { istruzioni da eseguire se si verifica l'errore ); }
file CounterException.java
public class CounterException extends Exception { String message; public CounterException (String msg) { message = msg; } public String getErrorMessage() { return message; } }
CounterException
getErrorMessage()
in modo da dare un messaggio di errore piu' significativo
file Counter.java
public class Counter { int value = 0; int topValue = 5; public int increment() throws CounterException { if (value >= topValue) throw (new CounterException("Counter Exceeded")); value ++; return value; } public int getValue() { return value; } }
CounterException
file MyApplication.java
public class MyApplication { public static void main (String args[]) { Counter c1 = new Counter(); System.out.println("Counter 1 has value "+c1.getValue()); try { for (int i=1; i<10; i++) { c1.increment(); System.out.println("Counter 1 is now "+c1.getValue()); } } catch (CounterException e) { System.out.println(e.getErrorMessage()); } } }
CounterException
getErrorMessage()
della stessa per ottenere un messaggio piu' significativo.
import java.awt.*; import java.applet.*; import java.lang.*; import java.util.Date; public class Clock extends Applet implements Runnable { Font f1 = new Font("Serif",Font.BOLD, 24); Date d; Thread a; public void start() { if (a == null) { a = new Thread(this); a.start(); } } public void stop() { if (a != null) { a = null; } } public void run() { while(a != null) { d = new Date(); repaint(); try { Thread.sleep(1000);} catch (InterruptedException e) { } } } public void paint(Graphics g) { g.setFont(f1); g.drawString(d.toString(),10,50); } }Vedete qui l'applet in funzione.
Runnable
cosi' puo' definire
il metodo run
di Thread.
Thread a
start
dell'applet e consiste nell'istanziare l'oggetto Thread
e nel richiamare il suo metodo start
null
per accertarsi che la multiprogrammazione
sia davvero terminata(cioe' l'oggetto a
non esiste).
stop
dell'applet
(importante per non lasciare programmi inutili in esecuzione) distruggendo
l'oggetto Thread con a=null
.
run
e' un ciclo da eseguire solo finche' l'oggetto
Thread esiste e contiene l'aggiornamento dell'ora ogni secondo e il richiamo
a repaint
per far aggiornare l'orologio.
import java.awt.*; import java.applet.*; import java.lang.*; import java.util.Date; public class actor1 extends Applet { Font f1 = new Font("Serif",Font.BOLD, 24); Date d; MyThread a; public void start() { if (a == null) { a = new MyThread(this); a.start(); } } public void stop() { if (a != null) { a = null; } } public void paint(Graphics g) { g.setFont(f1); g.drawString(d.toString(),10,50); } } class MyThread extends Thread{ actor1 act; public MyThread(actor1 act1){ super(); act = act1; } public void run() { while(true) { act.d = new Date(); act.repaint(); try { Thread.sleep(1000);} catch (InterruptedException e) { } } } }Vedete qui l'applet in funzione.
a
di tipo MyThread
.
start
e stop
sono identici.
MyThread
ha un costruttore che permette il passaggio
dell'indirizzo dell'applet e la sua assegnazione alla variabile act
di MyThread
. Questo e' necessario per permettere alla classe
di accedere metodi e variabili dell'applet.
super()
per richiamare il costruttore di Thread
in modo che avvenga la normale
inizializzazione.
run
e' identico.
public
, possiamo inserirla nello stesso
file contenente l'applet.
import java.applet.*; import java.awt.*; public class Anim0 extends Applet { int x,y,r; public void init() { x = 0; y=200; r=50; while(true) { for (x = r; x <= size().width ; x=x+1) { repaint(); } } } public void paint(Graphics g) { g.setColor(Color.red); g.fillOval(x,y,2*r,2*r); } }Vedete qui l'applet in funzione.
import java.applet.*; import java.awt.*; public class Anim1 extends Applet implements Runnable { Thread animazione; int x,y,r; public void init() { x = 0; y=200; r=50; } public void start() { if (animazione == null) { animazione = new Thread(this); animazione.start(); } } public void stop() { if (animazione != null) { animazione = null; } } public void run() { while(animazione != null) { for (x = r; x <= size().width ; x=x+1) { repaint(); try { Thread.sleep(100);} catch (InterruptedException e) { } } } } public void paint(Graphics g) { g.setColor(Color.red); g.fillOval(x,y,2*r,2*r); System.out.println("x,y,z="+x+" "+y+" "+r); } }Vedete qui l'applet in funzione.
repaint
.
paint
ridisegnando l'applet provvede a cancellare l'immagine precedente.Questa cancellazione provoca un'animazione imperfetta.
import java.applet.*; import java.awt.*; public class Anim2 extends Applet implements Runnable { Thread animazione; int x,y,r; Image o; Graphics og; public void init() { x = 0; y=200; r=50; o = createImage(size().width,size().height); og = o.getGraphics(); } public void start() { if (animazione == null) { animazione = new Thread(this); animazione.start(); } } public void stop() { if (animazione != null) { animazione = null; } } public void run() { while(animazione!=null) { for (x = 0; x <= size().width ; x=x+1) { repaint(); try { Thread.sleep(100);} catch (InterruptedException e) { } } } } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { og.setColor(Color.white); og.fillRect(0,0,size().width,size().height); og.setColor(Color.red); og.fillOval(x,y,2*r,2*r); g.drawImage(o, 0, 0 ,this); System.out.println("x,y,z="+x+" "+y+" "+r); } }Vedete qui l'applet in funzione. In questo caso sono stati applicati due "trucchi" che migliorano l'animazione:
Graphics
collegato all'immagine. In pratica una volta creati questi oggetti con le istruzioni:
o = createImage(size().width,size().height); og = o.getGraphics();possiamo eseguire il disegno in memoria usando
og
invece di g
. Quando il disegno e' pronto lo trasferiamo con un sol colpo nella finestra dell'applet con:
g.drawImage(o, 0, 0 ,this);Da notare che ora dobbiamo procedere noi a cancellare l'immagine precedente con l'istruzione:
og.setColor(Color.white); og.fillRect(0,0,size().width,size().height);L'uso della multiprogrammazione crea il problema della sincronizzazione tra diversi processi in competizione per la stessa risorsa. Questo succede anche nell'applet precedente dove l'oggetto Image deve essere condiviso da 2 processi:quello che richiama il metodo paint e il processo che fa andare l'animazione.Percio' l'accesso all'immagine deve essere controllato. Questo lo si fa dichiarando un intero metodo o anche una singola istruzione
synchronized
.
import java.applet.*; import java.awt.*; public class Anim4 extends Applet implements Runnable { Thread animazione; int x,y,r; Image o; Graphics og; public void init() { x = 0; y=200; r=50; } public void start() { if (animazione == null) { animazione = new Thread(this); animazione.start(); } } public void stop() { if (animazione != null) { animazione = null; } } public void run() { while(animazione != null) { for (x = 0; x <= getSize().width ; x=x+1) { createNextFrame(); repaint(); synchronized(this){ try { wait(100);} catch (InterruptedException e) { } } } } } synchronized void createNextFrame(){ if(o==null){ o = createImage(getSize().width,getSize().height); og = o.getGraphics(); } og.setColor(Color.white); og.fillRect(0,0,getSize().width,getSize().height); og.setColor(Color.red); og.fillOval(x,y,2*r,2*r); } public void update(Graphics g) { paint(g); } synchronized public void paint(Graphics g) { g.drawImage(o, 0, 0 ,this); } }Vedete qui l'applet in funzione. Dichiarando synchronized i due metodi paint e nextFrame che accedono alla stessa risorsa(l'immagine offline) si evita che possano intralciarsi. Infatti i due metodi sono eseguiti in due diversi Thread e potrebbe accadere che la paint aggiorni l'immagine mentre la nextFrame sta aggiornando la stessa.Solo uno dei due metodi puo' essere in esecuzione in un dato momento.
synchronized(this){statements}
.
import java.awt.*; import javax.swing.*; public class Anim1 extends JApplet implements Runnable { Display disegno; Thread animazione; int x,y,r; public void init() { disegno = new Display(); setContentPane(disegno); x = 0; y=200; r=50; } public void start() { if (animazione == null) { animazione = new Thread(this); animazione.start(); } } public void stop() { if (animazione != null) { animazione = null; } } public void run() { while(true) { for (x = r; x <= disegno.getSize().width ; x=x+1) { disegno.repaint(); try { Thread.sleep(100);} catch (InterruptedException e) { } } } } class Display extends JPanel{ public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.red); g.fillOval(x,y,2*r,2*r); } } }Vedete qui l'applet in funzione.
Timer
che
genera eventi
a intervalli prestabiliti. (Parleremo di
eventi nel prossimo seminario: ma in pratica e' come se un utente pigiasse
un tasto a intervalli prestabiliti).Invece della run
ora abbiamo
la actionPerformed
che aggiorna l'immagine eseguendo l'animazione.
Per poterla definire e' necessario implementare l'interfaccia ActionListener
.
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Anim2 extends JApplet implements ActionListener { Display disegno; Timer timer; int x,y,r; Image o; Graphics og; public void init() { disegno = new Display(); setContentPane(disegno); x = 0; y=200; r=50; } public void start() { if (timer == null) { timer = new Timer(100,this); timer.start(); } } public void stop() { if (timer != null) { timer.stop(); } } public void actionPerformed(ActionEvent e) { x = x + 1; if(x>disegno.getSize().width)x = 0; disegno.repaint(); } class Display extends JPanel{ public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.red); g.fillOval(x,y,2*r,2*r); } } }Vedete qui l'applet in funzione.
import java.applet.Applet; import java.awt.Graphics; public class Lista extends Applet{ ListNode inizio = new ListNode(0); public void init() { ListNode prossimo = inizio; for (int i = 1; i <= 10; i++) { prossimo.next = new ListNode(i); prossimo = prossimo.next; } } public void paint( Graphics g) { ListNode prossimo=inizio; g.drawString("Contenuto della lista: ", 5, 20); for (int i = 0; i <= 10; i++) { g.drawString(" "+prossimo.data, 50, i*10+40); prossimo = prossimo.next; } } } class ListNode { public ListNode next = null; public int data; public ListNode(int data) { this.data = data; } }Guardate l'applet in funzione.
ListNode
che ha come variabili :data
per contenere il dato intero e next
per puntare al prossimo nodo nella lista.
ListNode
come classe interna all'applet.
inizio
e quindi assegnare questo valore a prossimo
.
L'istruzione:prossimo = prossimo.next;ci permette di traversare la lista.
Vector
si usa ArrayList
,Hastable
e' diventata HashMap e HashSet
e l'iteratore invece di Enumeration
si chiama Iterator
(Confusi !?)
array
S
file Stack.java
public interface Stack{ void push(Object o) throws StackException; Object pop() throws StackException; Object top() throws StackException; int size(); }
file Stack1.java
public class Stack1 implements Stack{ int max; int size; Object[] dati; public Stack1(int dim){ dati = new Object[dim]; max = dim; size = 0; } public void push(Object o) throws StackException { if(size == max) throw new StackException("massimo dello stack superato"); dati[size++] = o; } public Object pop() throws StackException { if(size <=0) throw new StackException("stack vuoto"); return dati[--size]; } public Object top() throws StackException { if(size <=0) throw new StackException("stack vuoto"); return dati[size-1]; } public int size(){return this.size;} }
Object
.
Stack
lanciando le eccezioni StackException
con gli opportuni messaggi
quando lo stack supera le dimensioni del vettore oppure e' vuoto.
file StackException.java
public class StackException extends Exception{ StackException(String msg){super(msg);} }Ecco un altro modo di ridefinire un'eccezione in modo da personalizzare il messaggio che da(confronta con l'Applicazione 2).
file TestStack.java
class TestStack{ public static void main(String[] args){ Stack1 s = new Stack1(5); try { System.out.println("Dimensioni iniziali ="+s.size()); s.push("uno"); s.push(new Integer(2)); s.push(new Double(3.)); s.push("quattro"); s.push("cinque"); s.push("sei"); } catch(StackException e){ System.out.println(e);} try { System.out.println("Oggetto top = "+s.top()); String s1 = (String)s.pop(); String s2 = (String)s.pop(); System.out.println(s1+" "+s2); int n = s.size(); for(int i=0;i < n;i++){ System.out.println("Oggetto "+i+" = "+s.pop()); } s.pop(); } catch(StackException e){ System.out.println(e);} } }
Output
Dimensioni iniziali =0 StackException: massimo dello stack superato Oggetto top = cinque cinque quattro Oggetto 0 = 3.0 Oggetto 1 = 2 Oggetto 2 = uno StackException: stack vuoto
NomeClasse a = (NomeClasse)s.pop();ma perche' la cosa funzioni bisogna ricordarsi in qualche modo il tipo di oggetto caricato.
(Nome_sottoclasse)
e puo' dar luogo a una
ClassCastException.Si usa up(su) e down(giu') perche' nella
rappresentazione schematica dell'ereditarieta' la classe madre e' di
solito rappresentata sopra la classe figlia collegata a questa da
una freccia con la punta in alto.
Vector
S
file Stack2.java
import java.util.*; public class Stack2 implements Stack{ Vector dati; public Stack2(){ dati = new Vector(); } public void push(Object o) { dati.addElement(o); } public Object pop() throws StackException { if(dati.size() ==0) throw new StackException("stack vuoto"); int i = dati.size()-1; Object o = dati.elementAt(i); dati.removeElementAt(i); return o; } public Object top() throws StackException { if(dati.size() ==0) throw new StackException("stack vuoto"); return dati.elementAt(dati.size()-1); } public int size(){return dati.size();} }
Vector
,fornito insieme ad altri contenitori in java.util,puo' crescere a piacere ed e' gia' un contenitore generico di oggetti.
Vector
addElement,
elementAt, removeElementAt, size
per manipolare il contenitore.
ArrayList
S
file Stack2.java
import java.util.*; public class Stack2 implements Stack{ ArrayList dati; public Stack2(){ dati = new ArrayList(); } public void push(Object o) { dati.add(o); } public Object pop() throws StackException { if(dati.size() ==0) throw new StackException("stack vuoto"); int i = dati.size()-1; Object o = dati.get(i); dati.remove(i); return o; } public Object top() throws StackException { if(dati.size() ==0) throw new StackException("stack vuoto"); return dati.get(dati.size()-1); } public int size(){return dati.size();} }
ArrayList
in java.util puo' crescere a piacere ed e' gia' un contenitore generico di oggetti.
ArrayList
add,
get, remove, size
per manipolare il contenitore.
Vector
per caricare una serie di oggetti, quindi
l'oggetto Enumeration
per stamparne il contenuto. Ripetete
la stessa cosa con una ArrayList
e un Iterator
.
S
file TestEnum.java
import java.util.*; class TestEnum{ public static void main(String[] args){ Vector v = new Vector(); v.addElement("uno"); v.addElement(new Integer(2)); v.addElement(new Double(3.)); v.addElement("quattro"); v.addElement("cinque"); v.addElement("sei"); System.out.println("Dimensioni del contenitore ="+v.size()); for (Enumeration e = v.elements() ; e.hasMoreElements() ;) { System.out.println(e.nextElement()); } } }
Enumeration
non e' in effetti che un'interfaccia
che contiene i soli metodi hasMoreElements
e nextElement
.
elements
e' un metodo di Vector
che ritorna
un oggetto enumeration
collegato allo stesso.
Enumeration
permette di esaminare gli
elementi in esso contenuti uno a uno, in maniera sequenziale, con le istruzioni:for (Enumeration e = v.elements() ; e.hasMoreElements() ;) { System.out.println(e.nextElement()); }
file TestEnum1.java
import java.util.*; class TestEnum1{ public static void main(String[] args){ ArrayList v = new ArrayList(); v.add("uno"); v.add(new Integer(2)); v.add(new Double(3.)); v.add("quattro"); v.add("cinque"); v.add("sei"); System.out.println("Dimensioni del contenitore ="+v.size()); for (Iterator iter = v.iterator() ; iter.hasNext() ;) { System.out.println(iter.next()); } } }Tutti i contenitori e gli iteratori di Java sono in
java.util
che dalla versione 2 di Java contiene molte piu' classi di questo tipo.
Sono cambiati anche i nomi delle classi. Ad esempio l'iteratore ora
non e' piu' realizzato da Enumeration
ma da Iterator
.
Object
permettono di scrivere algoritmi generici che funzionano per qualsiasi tipo di oggetto. Alle collezioni sono inoltre associati
dei particolari oggetti iterator
che permettono di attraversare la collezione attraverso i metodi next()
e hasNext()
.
Object
madre di tutte le classi, e'
completamente diversa.