Objektno programiranje 2
V tej lekciji bom spoznali osnovne koncepte objektnega
programiranja v Javi:
Objektne in statične komponente in metode
Dedovanje in abstraktni razredi
Prekrivanje
Določila public
, private
in protected
Objekta this
in super
Osnove vmesnikov
Izjeme
Objektne in statične metode in komponente
Vemo že, da vsak objekt sestoji iz objektnih komponent in
objektnih metod.
Poleg tega obstajajo v Javi še statične metode in
statične komponente. (Statične metode se v
neobjektnih programskih jezikih imenujejo "funkcije" ali
"procedure", statične komponente pa se imenujejo "globalne
spremenljivke".)
Pojasnimo razliko med statičnimi in objektnimi komponentami.
Obravnavajmo razred
Foo
:
1
2
3
4
5
6
7
8
| public class Foo {
static int x = 12;
int y;
public Foo(int z) {
this.y = z;
}
} |
Razred ima eno statično komponento
x
in eno objektno
(nestatično) komponento
y
. Kako razumeti vsako od njih?
Velja načelo:
Statične komponente so vsebovane v razredu, objektne
komponente pa v objektih.
Vsak objekt vsebuje svojo kopijo objektnih komponent, vsaka
statična komponenta pa vedno obstaja v eni sami kopiji.
|
Denimo, da izvedemo naslednja ukaza:
1
2
| Foo t1 = new Foo(42);
Foo t2 = new Foo(30); |
Potem imamo
dva objekta, zato imamo dve kopiji komponente
y
, po eno v vsakem objektu. Ker je komponenta
x
statična, vedno obstaja v eni sami kopiji, tudi če
nimamo nobenih objektov razreda
Foo
:
Naloga 1: Objektni zajci
Dan je razred
Zajec
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public class Zajec {
static double min_masa = 1.5; // najmanjsa dovoljena masa za zakol v kg
static int max_starost = 48; // najvecja dopustna starost zajkle v mesecih
String serijska; // serijska stevilka zajca
boolean spol; // true = moski, false = zenska
double masa; // masa zajca ob zadnjem pregledu
public Zajec(String s, boolean sp, double m) {
serijska = s; spol = sp; masa = m;
}
// tu bi napisali ostale konstruktorje in metode
...
} |
Denimo, da izvedemo naslednje ukaze:
1
2
3
4
5
| Zajec z1 = new Zajec("1238-12-0", false, 0.12);
Zajec z2 = new Zajec("1238-12-1", true, 0.09);
Zajec z3 = new Zajec("1238-12-2", true, 0.11);
Zajec.min_masa = 1.4;
z1.masa = 0.10; |
Nariši diagram, ki ponazarja koliko objektov tipa
Zajec
imamo, kakšne komponente vsebuje in kakšne so
njihove vrednosti. Diagram naj tudi prikaže vse statične
komponente in njihove vrednosti.
Koliko kopij komponente masa
se naredi, ko izvedemo
te ukaze? Kakšne so njihove vrednosti? Napiši ukaze, s
katerimi vse kopije komponente masa
nastavimo na
vrednost 2.0
.
Koliko kopij komponente max_starost
se naredi, ko
izvedemo zgornje ukaze? Kakšne so njihove vrednosti? Napiši
ukaze, s katerimi vse kopije komponente max_starost
nastavimo na vrednost 36
.
Namig
Zgleduj se po primeru razreda Foo
iz lekcije.
Zapomni si: statične komponente vedno nastopajo v eni sami
kopiji in so vsebovane v razredu, objektne komponente pa so
vsebovane v objektih (in jih je toliko kot je objektov).
[
rešitev]
Kako vemo, ali naj bo komponenta statična ali objektna? Statične
komponente so tiste, ki so skupne za celoten program. Na
primer, v prejšnji vaji je min_masa
statična
komponenta, ker je najmanjša dovoljena masa zajca število, ki je
skupno za ves program (za vse zajce). Komponenta masa
je objektna, ker ima vsak zajec svojo maso.
Kaj pa razlika med statičnimi in objektnimi metodami?
Najpomembnejša razlika je tale:
Statično metodo bla() v razredu Foo lahko
vedno izvedemo z ukazom Foo.bla() . Znotraj statične
metode objekt this ni definiran, ker se statična
metode ne kliče na objektu.
Objektno metodo hej() v razredu Foo lahko
izvedemo, če imamo neki objekt x razreda
Foo , z ukazom x.hej() . Znotraj metode
hej() označuje this objekt, na katerem je
metoda poklicana.
|
Na primer, če imamo razred
1
2
3
4
5
6
7
8
9
10
11
12
| public class Foo {
static int x = 12;
int y;
public Foo(int z) {
this.y = z;
}
static int f(int a) { return x + a; }
int g(int a) { return this.y + x + a; }
} |
potem ima statična metoda
f
dostop do komponente
x
. Dostopa do komponente
y
nima, saj znotraj
statične metode ne moremo pisati
this.y
.
Objektna metoda
g
pa ima dostop do komponente
this.y
, kjer je
this
objekt, na katerem je
metoda
g
klicana.
Na primer:
1
2
3
4
5
6
| int p = Foo.f(7); // p == 12 + 7 == 19
Foo.x = -3;
int q = Foo.f(5); // q == -3 + 5 == 2
Foo t = new Foo(100);
Foo s = new Foo(200);
int r = t.g(50); // r == 100 + (-3) + 50 == 147 |
Naloga 2
Nariši diagrame, ki prikazujejo statične komponente in
objekte za zgornji primer. Povej, kako se spreminja število
objektov in vrednosti komponent, ko se izvajajo ukazi iz
primera.
Ali ima klic metode t.g(50)
dostop do komponente
s.y
? Do katerih komponent ima dostop?
Namig
Oglej si rešitev prve naloge. Diagrame nariši na vajah pod
budnim očesom asistenta. Tudi na predavanjih smo risali take
diagrame.
Zapomnimo si: objektna metoda ima dostop do statičnih
komponent in do objektnih komponent objekta, na katerem je
poklicana.
[
rešitev]
Dedovanje
Dedovanje je metoda objektnega programiranja, s katero
organiziramo in povežemo razrede, ki sestavljajo program.
Ogledali si bomo klasični primer dedovanja geometrijskih
likov.
Denimo, da pišemo program, v katerem imamo opravka z
geometrijskimi liki, kot so trikotnik, krog, kvadrat, ipd. Za
vsak lik poznamo njegovo lego (x, y) v ravnini. Denimo, da mora
program znati translirati lik za dani vektor in izračunati
njegovo ploščino. Vprašanje je, kako bi to naprogramirali.
(Pravi program bi moral znati dosti več, a ti dve metodi bosta
zadostovali za naš preprost primer.)
Za vsak lik, ki ga program pozna, napravimo svoj razred. Denimo,
da želimo delati s trikotniki, krogi in kvadrati. Torej bomo
definirali tri razrede Trikotnik
, Krog
in
Kvadrat
.
Po drugi strani bi bilo dobro definirati splošen razred
Lik
, ki bi združeval vse like, s katerimi zna program
delati. Z diagramom bi to prikazali takole:
Kar je vsem likom skupnega, bi dali v razred Lik
, kar
pa je za vsak lik specifično, bi spadalo v pripadajoči razred.
Na primer, pozicija na ravnini je vsem likom skupna, zato je to
del razreda Lik
. Krog ima polmer r
, kvadrat
ima dolžino stranice a
, trikotnik pa ima pozicije
oglišč. To so podatki, ki spadajo v vsak posamezni razred.
Pravimo, da so razredi
Trikotnik
,
Krog
in
Kvadrat
podrazredi razreda
Lik
, ali da
je razred
Lik
njihov
nadrazred. V Javi povemo,
da je en razred podrazred nekega drugega razreda z določilom
extends
:
public class Trikotnik extends Lik {
...
} |
Besedica "extends" pomeni "razširi" in je uporabljena zato, ker
razred
Trikotnik
vsebuje vse komponente in metode, ki
jih vsebuje razred
Lik
(in še dodatne komponente in
metode, ki jih razred
Lik
morda nima).
Razrede
Lik
,
Trikotnik
,
Krog
in
Kvadrat
bi napisali takole:
Lik.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public abstract class Lik {
double x;
double y;
public Lik(double x, double y) {
this.x = x;
this.y = y;
}
public void transliraj(double dx, double dy) {
x = x + dx;
y = y + dy;
}
public abstract double ploscina();
} |
Krog.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
| public class Krog extends Lik {
double r; // polmer
public Krog(double x, double y, double r) {
super(x, y);
this.r = r;
}
public double ploscina() {
return Math.PI * r * r;
}
} |
Kvadrat.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
| public class Kvadrat extends Lik {
double a; // dolzina stranice
public Kvadrat(double x, double y, double a) {
super(x, y);
this.a = a;
}
public double ploscina() {
return a * a;
}
} |
Trikotnik.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public class Trikotnik extends Lik {
double x2, y2; // drugo oglisce
double x3, y3; // tretje oglisce
Trikotnik(double x, double y,
double x2, double y2,
double x3, double y3) {
super(x, y);
this.x2 = x2; this.y2 = y2;
this.x3 = x3; this.y3 = y3;
}
public double ploscina() {
return 0.5 * Math.abs(x3*y - x2*y + x*y2 - x3*y2 - x*y3 + x2*y3);
}
} |
Oglejmo si vsakega od razredov bolj natačno. Vsak razred vsebuje
po en konstruktor. V konstruktorjih za podrazrede vidimo klic
super(x, y)
, s katerim pokličemo konstruktor nadrazreda
Lik
.
Razred Lik
vsebuje komponenti double x
,
double y
in objektno metodo void transliraj(double
dx, double dy)
. Razred Lik
vsebuje tudi
abstraktno deklaracijo metode double ploscina()
.
S to deklaracijo povemo, da mora vsak podrazred razreda
Lik
definirati tako metodo. Razred Lik
ne
vsebuje metode double ploscina()
, saj za splošni lik ne
moremo definirati metode, ki izračuna njegovo ploščino. Zato
pravimo, da je metode ploščina
samo abstraktno
deklarirana. Kadar je v razredu deklarirana abstraktna
metoda, s tem tudi celoten razred postane abstrakten.
Povzemimo:
public abstract class A {
...
abstract int f(int x);
...
} |
Vsak podrazred razreda A mora vsebovati metodo
int f(int x) . Razred A take metode ne
vsebuje.
Razred A je abstrakten, ker je v njem deklarirana
abstraktna metoda.
|
Ker je razred Krog
definiran z določilom "extends
Lik
", vsebuje vse komponente, ki jih vsebuje razred
Lik
. Torej vsebuje tri komponente, double x
,
double y
in double r
, ter dve metodi, void
transliraj(double dx, double dy)
in double
ploscina()
.
Razred Kvadrat
vsebuje tri komponente, double
x
, double y
in double a
, ter dve metodi,
void transliraj(double dx, double dy)
in double
ploscina()
.
Razred Trikotnik
pa vsebuje šest komponent, double
x
, double y
, double x2
, double
y2
, double x3
, double y3
, ter dve metodi,
void transliraj(double dx, double dy)
in double
ploscina()
.
Zapomnimo si, kako deluje določilo extends
:
class A extends B {
...
} |
Razred A podeduje komponente in metode
od razreda B . Objekti razreda A so hkrati tudi objekti razreda
B .
|
Krogi, kvadrati in trikotniki so liki. Uporabljamo jih takole:
1
2
3
4
5
| Lik kr = new Krog(2.0, 3.0, 1.0);
Lik kv = new Kvadrat(0.0, 2.0, 7.0);
kr.transliraj(-2.0, 3.0);
double p = kr.ploscina();
double q = kv.ploscina(); |
Naloga 3
V dokumentaciji o Javini standardni knjižnici poišči
podatke o razredu
Applet
in odgovori na naslednja
vprašanja:
Kateri razred je nadrazred razreda Applet
?
Ali ima Applet
kak podrazred?
Naštej vse razrede, od katerih Applet
podeduje
metode.
Od katerega razreda podeduje Applet
metodo
getWidth
?
Od katerega razreda podeduje Applet
metodo
resize
?
Katere metode podeduje Applet
od razreda
Panel
?
[
rešitev]
Naloga 4: Barvni liki
Primer dedovanja geometrijskih likov bomo še nekoliko
razširili, da bomo lahko like tudi risali na zaslon. Razredu
Lik
dodamo komponento barva
in abstraktno
metodo narisi
in ustrezno popravimo podrazrede.
Lik.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| import java.awt.Color;
import java.awt.Graphics;
public abstract class Lik {
double x, y;
Color barva;
public Lik(double x, double y) {
this.x = x;
this.y = y;
this.barva = Color.black;
}
public Lik(double x, double y, Color c) {
this.x = x;
this.y = y;
this.barva = c;
}
public void transliraj(double dx, double dy) {
x = x + dx;
y = y + dy;
}
public abstract double ploscina();
public abstract void narisi(Graphics g);
} |
Krog.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| import java.awt.*;
public class Krog extends Lik {
double r; // polmer
public Krog(double x, double y, double r) {
super(x, y);
this.r = r;
}
public Krog(double x, double y, double r, Color c) {
super(x, y, c);
this.r = r;
}
public double ploscina() {
return Math.PI * r * r;
}
public void narisi(Graphics g) {
g.setColor(this.barva);
g.fillOval((int)(this.x - this.r), (int)(this.y - this.r), (int)(2*r), (int)(2*r));
}
} |
Nato uporabimo razreda
Okno.java
in
Slika.java
za risanje
slik (kako delujeta, na tem mestu ne bomo razlagali) takole:
> Okno w = new Okno();
> w.prikazi();
> w.dodaj(new Krog(100, 100, 80, Color.red); |
Sestavi tudi podrazrede za kvadrat, trikotnik in
pravokotnik.
Sestavi podrazred KvadratNagnjen
razreda
Kvadrat
, ki predstavlja zasukan kvadrat.
Nariši lepo sliko!
Prekrivanje
Denimo, da imamo razred
Foo
in podrazred
Qux
,
ki sta definirana takole:
Foo.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
| public class Foo {
int x;
public Foo(int u) { this.x = u; }
public int bla() {
return this.x;
Foo a = new Foo(42);
Foo b = this(12);
}
} |
Qux.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
| public class Qux extends Foo {
int y;
public Qux(int u, int v) {
super(u);
this.y = v;
}
public int bla() {
return super.bla() + this.y;
}
} |
Metoda
bla
je definirana v razredu
Foo
. Ker
razred
Qux
deduje od
Foo
, podeduje tudi metodo
bla
. Vendar pa
Qux
definira tudi svojo lastno
metodo
bla
, ki
prekrije dedovano metodo
bla
. Do prekrite metode lahko znotraj razreda
Qux
dostopamo z
super.bla()
. Besedica
super
pomeni, da se sklicujemo na
nadrazred
(angl. "
superclass").
Primer:
1
2
3
4
| Foo a = new Foo(10); // a.x == 10
Foo b = new Qux(5, 7); // b.x == 5, b.y == 7
int p = a.bla(); // p == 10
int q = b.bla(); // q == 5 + 7 = 12 |
Naloga 5
Nadaljujmo zgornji primer. Kolikšna je vrednost
r
, ko izvedemo ukaz:
Namig
Nima smisla uganjevati. Napravi preizkus!
[
rešitev]
Določila public
, private
in protected
Ko definiramo razred vedno napišemo public class
...
in ko definiramo metodo, običajno uporabimo določilo
public
. Poleg določila public
pozna Java še
določili private
in protected
.
Za komponento ali metodo veljajo naslednja pravila o dostopu:
public Dostop imajo vsi razredi. private
Dostop ima samo razred, v katerem je metoda ali komponenta
definirana.
protected
Dostop imajo vsi razredi, ki so v istem paketu. O
paketih še nismo govorili in letos tudi ne bomo. Paket je
skupina razredov, ki tvorijo smiselno celoto (npr. paket
razredov za delo z datotekami java.io ).
Če definiramo metodo ali komponento in ne povemo kakšen dostop
ima, se privzame, da ima dostop protected .
|
Objekta this
in super
V Javi besedica this
pomeni objekt, na katerem se
izvaja objektna metoda. Vemo že, da je do komponente x
v objektu, na katerem se izvaja objektna metoda, dostopamo s
this.x
. Okrajšano to lahko pišemo tudi x
.
Podobno pravilo velja za dostop do objektne metode: namesto
this.f(x,y,z)
lahko pišemo f(x,y,z)
.
Poleg tega ima this
še eno uporabo: na začetku
konstruktorja lahko pokličemo kak drug konstruktor s klicem
this(...)
. To bomo ponazorili s primerom, najprej pa
naštejmo vsa pravila za uporabo this
.
this
objekt, na katerem se izvaja objektna metoda
this.x (krajši zapis: x ) komponenta x v objektu, na katerem se izvaja
objektna metoda. this.f(...) (krajši zapis: f(...) ) pokliči metodo f na objektu this . this(x,...,y)
pokliči konstruktor z argumenti x,...,y ;
ta uporaba je možna le na začetku konstruktorja.
|
Naslednji primer prikazuje, kako se uporabi
this
za
klic konstruktorja:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public class Foo {
int x;
int y;
int z;
public Foo(int x, int y) {
this.x = x;
this.y = y;
this.z = x + y;
}
public Foo(int x) {
this(x, x + 2);
this.z = 1;
}
} |
Ko izvedemo ukaz
se izvede 12. vrstica z vrednostjo
x = 20
. V 13.
vrstici se pokliče konstruktor za razred
Foo
z
argumentoma
20
in
22
. Izvajanje se prenese v
konstruktor v 6. vrstici z vrednostma
x = 20, y = 22
. V
7., 8. in 9. vrstici se nastavijo komponente
this.x =
20
,
this.y = 22
in
this.z = 42
. Klic tega
konstruktorja se zaključi in izvajanje se vrne v 14. vrstico,
kjer se nastavi
this.z = 1
. Končni rezultat je objekt
a
razreda
Foo
, ki ima komponente
a.x == 20
a.y == 22
a.z == 1 |
Poleg
this
pozna Java še objekt
super
. Denimo, da imamo razred
Foo
in podrazred
Qux
:
public class Foo {
int x;
public void mojaMetoda() {
System.out.println("Ti si ena krava.\n");
}
}
public class Qux extends Foo {
int y;
public void mojaMetoda() {
System.out.println("Ti si ena koza.\n");
}
public void f() {
this.mojaMetoda();
super.mojaMetoda();
}
} |
Ko izvedemo ukaz:
se na zaslon izpiše:
Ti si ena koza.
Ti si ena krava. |
Vidimo, da se pri klicu
this.mojaMetoda()
pokliče
objektna metoda
mojaMetoda()
iz razreda
Qux
,
pri klicu
super.mojaMetoda()
pa se pokliče objektna
metoda
mojaMetoda()
iz
nadrazreda razreda
Qux
.
public class Foo {
int x;
public void g() { ... }
}
public class Qux extends Foo {
int x;
public void g() { ... }
} |
V objektni metodi razreda
Qux
je
super
objekt,
na katerem se je poklicala metoda, vendar se ga obravnava kot
pripadnika
nadrazredaFoo
. Torej pomeni:
this.x
: komponenta x
iz razreda Qux
super.x
: komponenta x
iz razreda Foo
this.g()
: klic metode g
iz razreda Qux
super.g()
: klic metode g
iz razreda Foo
Osnove vmesnikov
Poleg razredov (class) Java pozna še en osnovni konstrukt, ki se
imenuje vmesniki (interface). V tej lekciji se z
vmesniki ne bomo preveč ukvarjali, le toliko, da bomo znali
uporabljati vmesnike iz Javine standardne knjižnice.
Vmesnik sestoji iz seznama
deklaracij metod. Na primer:
KomunikacijskaNaprava.java |
---|
1
2
3
4
5
6
| public interface KomunikacijskaNaprava {
public boolean poklici(String stevilka);
public void prekini_zvezo();
public void poslji_sporocilo(String s);
public String sprejmi_sporocilo();
} |
KomunikacijskaNaprava
je vmesnik (
interface
)
in ne razred (
class
). V njem so deklarirane štiri
metode za komunikacijo.
Vmesnik uporabimo z določilom "
implements
", takole:
public class Mobitel implements KomunikacijskaNaprava {
...
public boolean poklici(String stevilka) { ... }
public void prekini_zvezo() { ... }
public void poslji_sporocilo(String s) { ... }
public String sprejmi_sporocilo() { ... }
...
} |
S tem smo povedali, da razred
Mobitel
ustreza vmesniku
KomunikacijskaNaprava
. To
pomeni, da vsebuje vse metode, ki so deklarirane v
KomunikacijskaNaprava
. Vmesnik uporabimo takole:
KomunikacijskaNaprava m = new Mobitel(...);
if (m.poklici("014766500")) {
m.poslji_sporocilo("Pridem cez 15 minut.");
m.prekini_zvezo();
} else {
System.out.println("Zasedeno.\n");
} |
public class A implements I {
...
} |
Razred
A
ustreza vmesniku
I
. To pomeni,
da
A
vsebuje vse metode, ki so deklarirane v vmesniku
I
.
Razred lahko ustreza večim vmesnikom. V tem primeru naštejemo
vse vmesnike, ločene z vejicami:
public class SuperMobitel implements KomunikacijskaNaprava, Kalkulator {
...
} |
Razred torej vedno deduje od kvečjemu enega nadrazreda, ustreza
pa lahko večim vmesnikom.
Naloga 6
V dokumentaciji o Javini standardni knjižnici poišči podatke
o razredu
Applet
in odgovori na naslednja
vprašanja:
Katerim vmesnikom zadošča Applet
?
Katere metode zahteva vmesnik ImageObserver
?
Čemu je namenjen vmesnik ImageObserver
?
[
rešitev]
Izjeme
Izjema (angl. "exception") je poseben dogodek, ki se
pripeti, kadar pride v programu do napake. Najpogostejše izjeme
v Javi so:
ArithmeticException
Sproži se pri deljenju z nič:
Delenje.java |
---|
1
2
3
4
5
6
| public class Delenje {
public static void main(String[] args) {
int a = 0;
int b = 20/a;
}
} |
> java Delenje
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Delenje.main(Delenje.java:4) |
ArrayIndexOutOfBoundsException
Sproži se pri naslavljanju neobstoječega elementa tabele:
Tabela.java |
---|
1
2
3
4
5
6
| public class Tabela {
public static void main(String[] args) {
int[] a = {0, 3, 1, 7};
int b = a[20];
}
} |
> java Tabela
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at Tabela.main(Tabela.java:4) |
StringIndexOutOfBoundsException
Sproži se, če program dostopa do neobstoječega indeksa v
nizu:
Niz.java |
---|
1
2
3
4
5
6
| public class Niz {
public static void main(String[] args) {
String s = "abcdef";
char c = s.charAt(31);
}
} |
> java Niz
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 31
at java.lang.String.charAt(String.java:438)
at Niz.main(Niz.java:4) |
NullPointerException
Sproži se, če program kliče metodo na nedefiniranem
objektu
null
:
Null.java |
---|
1
2
3
4
5
6
7
| public class Null {
static String s;
public static void main(String[] args) {
char c = s.charAt(3);
}
} |
> java Null
Exception in thread "main" java.lang.NullPointerException
at Null.main(Null.java:5) |
FileNotFoundException
Sproži se, ko program odpre datoteko, ki ne obstaja:
Datoteka.java |
---|
1
2
3
4
5
6
7
| import java.io.*;
public class Datoteka {
public static void main(String[] args) throws IOException {
FileReader f = new FileReader(args[0]);
}
} |
> java Datoteka blabla.txt
Exception in thread "main" java.io.FileNotFoundException:
blabla.txt (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:106)
at java.io.FileInputStream.<init>(FileInputStream.java:69)
at java.io.FileReader.<init>(FileReader.java:42)
at Datoteka.main(Datoteka.java:5) |
Ko se sproži izjema, se prevajanje programa prekine. To ni vedno
zaželeno. Na primer, če uporabnik navede neobstoječo datoteko,
potem je bolje, če se program ne prekine, ampak izpiše
sporočilo, da taka datoteka ne obstaja.
Kadar napišemo metodo, ki bi lahko sprožila izjemo, moramo v
deklaraciji metode to povedati z določilom
throws
. Če pozabimo dodati
throws
, nas
prevajalnik opozori na napako.
public int mojaMetoda(...) throws ImeIzjeme {
...
} |
V Javi lahko izjeme
prestrežemo s konstruktom
try {
A;
}
catch (ImeIzjeme e) {
B;
} |
To pomeni:
"Izvedi A
. Če se med izvajanjem sproži
izjema ImeIzjeme
, jo prestrezi in izvedi
B
."
Na primer, napišimo program, ki z ukazne vrstice dobi ime
datoteke in izpiše njeno vsebino na zaslon. Če datoteka ne
obstaja, izpiše sporočilo o napaki:
IzpisiDatoteko.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| import java.io.*;
public class IzpisiDatoteko {
public static void main(String[] args) {
String ime = args[0];
try {
BufferedReader datoteka = new BufferedReader(new FileReader(ime));
while(datoteka.ready()) {
System.out.println(datoteka.readLine());
}
datoteka.close();
}
catch (FileNotFoundException e) {
System.out.println("Datoteka " + ime + " ne obstaja.");
}
}
} |
> java IzpisiDatoteko Niz.java
public class Niz {
public static void main(String[] args) {
String s = "abcdef";
char c = s.charAt(31);
}
}
> java IzpisiDatoteko blablabla.txt
Datoteka blablabla.txt ne obstaja. |
Naloga 7
Popravi program
IzpisiDatoteko.java
tako, da v primeru, ko datoteka ne obstaja, uporabnika
vpraša za novo ime. Če uporabnik vnese prazno ime (pritisne
Enter), naj se program konča, sicer pa naj poskusi z novim
imenom. Če po treh poskusih uporabnik še vedno ni vnesel
imena obstoječe datoteke, naj se program konča.
Namig
Uporabi dve pomožni spremenljivki. Prva je boolean
uspeh in ima vrednost false. Ko program
uspešno izpiše datoteko, naj jo nastavi na true.
Druga pomožna spremenljivka šteje, koliko je bilo neuspešnih
poskusov. Če to število preseže 3, program konča z delom.
Shema glavnega dela programa:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| import java.io.*;
public class IzpisiDatoteko2 {
public static void main(String[] args) throws IOException {
String ime = args[0];
boolean uspeh = false;
int neuspehi = 0;
do {
try {
BufferedReader datoteka =
new BufferedReader(new FileReader(ime));
while(datoteka.ready()) {
System.out.println(datoteka.readLine());
}
datoteka.close();
uspeh = true;
}
catch (FileNotFoundException e) {
neuspehi = neuspehi + 1;
// tu vprasamo uporabnika za novo ime
}
}
} while (//tu napisi ustrezni pogoj);
}
} |
[
rešitev]