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 actdi 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.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.
inizio e quindi assegnare questo valore a prossimo.
L'istruzione:prossimo = prossimo.next;ci permette di traversare la lista.
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.
Vector per caricare una serie di oggetti, quindi
l'oggetto Enumeration per stamparne il contenuto.
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());
}
java.util
che dalla versione 2 di Java contiene molte piu' classi di questo tipo.