Transcript

OBJEKTNO ORIJENTISANO PROGRAMIRANJE

PREDAVANJE 13: OBRADA GREŠAKA I ULAZNO-IZLAZNE OPERACIJE (TEKSTUALNI FAJLOVI, TASTATURA I EKRAN)

Miloš Kovačević

Đorđe Nedeljković

1 /21

OSNOVNI KONCEPTI- Priroda grešaka u programu

- Klijent-server koncept i obaveštavanje klijenta o greški

- Izuzeci

- Obrada izuzetaka (try/catch/finally)

- Tekstualni fajlovi – čitanje i pisanje

- Čitanje sa tastature

- Ispis na ekran

2 /21

PRIRODA GREŠAKA U PROGRAMU- Sintaksne greške

- nepravilna upotreba delova jezika (ključne reči, operatori, ...) pri kodiranju klasa

- otklanjaju se jednostavno pri prevođenju na upozorenje prevodioca

- if(a = 5){...} //treba == umesto =

- Logičke greške (bugs) - greške u logičkom postupku (sledu akcija) pri rešavanju problema

- otklanjaju se ne tako lako prilikom testiranja rada programa

- primeri: deljenje sa 0, objekat se nalazi u nepredviđenom stanju, korisnik unosi neadekvatne ulazne podatke, itd.

- Značajan utrošak programerskog vremena odlazi na testiranje implementacije klasa u cilju otklanjanja logičkih grešaka

- Programski modeli složenih sistema skoro uvek sadrže greške, od kojih se najveći broj otkloni pre puštanja na tržište, a ostale se otklanjaju tokom životnog ciklusa softvera

- Java olakšava proces prevazilaženja grešaka primenom koncepta izuzetaka

3 /21

KLIJENT-SERVER KONCEPT- Kada se nad objektom poziva neki njegov javni metod,

onda se on nalazi u ulozi servera (pružaoca usluge), a objekat koji poziva metod naziva se klijent (onaj koji potražuje uslugu)

- Isti objekat u toku vremena može se naći u obe uloge

- Primeri softverskih komponenti koje se nalaze u klijent-server relaciji:- Apache web server (isporučuje stranice sajta na zahtev) – Chrome web browser (klijent)

- Exchange mail server (čuva i isporučuje poštu) – Outlook mail klijent (pregleda i pravi mailove)4 /21

LOGIČKE GREŠKE – KAKO IH OTKLONITI

5 /21

public class RangLista{ // serverska klasa

private String[] ime; // indeks u nizu odnosi se

private double[] poeni; // na mesto u rang listi

public RangLista(int brojMesta){

ime = new String[brojMesta];

poeni = new double[brojMesta];

}

public void ubaci(int rb, String i, double p){

ime[rb - 1] = i; poeni[rb - 1] = p;

}

...

}

public class Klijent{ // klijentska klasa

public static void testRangLista(){

RangLista rl = new RangLista(10);

rl.ubaci(1, "Pera Perin", 100);

rl.ubaci(15, "Mika Mikic", 2);

}

}

Moguća greška ukoliko je redni broj van broja predviđenih mesta na listi.Server klase RangLista ovde “puca“ za nekorektan ulaz rb!

Poruka o greški u BlueJ-u

- Server se štiti od grešaka uzrokovanih pogrešnim ulaznim podacima (parametri metoda) primenom defanzivnog programiranja (ekstenzivna upotreba if naredbi)

- U gornjem primeru korisnik dobija poruka o greški na ekranu. Ali, šta ako je klijent softverska komponenta koja ne čita poruke sa ekrana?

- Kako objekat klase RangLista vraća informaciju klijentu da je došlo do greške?

LOGIČKE GREŠKE – DEFANZIVNO PROGRAMIRANJE

6 /21

public void ubaci(int rb, String i, double p){

if(rb >= 1 && rb <= ime.length){

ime[rb - 1] = i; poeni[rb - 1] = p;

} else{ System.out.println("Nedozvoljeni redni broj"); }

}

OBAVEŠTAVANJE KLIJENTA O NASTALOJ GREŠKI

7 /21

- Vraćanje informaciju klijentu da je došlo do greške preko povratne vrednosti metode

- Pristup obaveštavanja putem povratne vrednosti ima tri nedostatka:- (1) Šta ako su sve povratne vrednosti metode mogući rezultati njenog izvršavanja?

- (2) Čak i kada (1) ne predstavlja problem, programer klijentske aplikacije nije u obavezida testira povratnu vrednost (u gornjem primeru da stavi if(s.skloni()...))

- (3) Šta se dešava kada konstruktor ne može pravilno da inicijalizuje objekat u početno stanje? (npr. kada u klasi RangLista neko prosledi negativan broj mesta na rang listi)

- Problemi obaveštavanja iz (1), (2) i (3) mogu se elegantno rešiti primenom koncepta izuzetaka (Exceptions)

// u serveru

public boolean ubaci(int rb){

if(rb >= 1 && rb <= ime.length){

...

return true;

} else { ... ; return false; }

}

// u klijentu

if(rl.ubaci(...)){

// operacija uspela

...

} else{

// operacija nije uspela

}

- Java obavezuje programera da predvidi mogućnost nastanka određenih tipova greški i da ih po nastanku obradi u cilju oporavka programa: greške koje se moraju obraditi- Primer: prilikom otvaranja datoteke sa diska, datoteka sa datim imenom ne postoji,

prilikom čitanja podataka koji dolaze sa mreže prekida se veza, ...

- Postoje i tipovi grešaka čiji nastanak nije obavezno predvideti i obraditi: greške koje se ne moraju obraditi- Primer: pristupanje elementu niza sa pogrešnim indeksom,

poziv metode nad objektnom promenljivom sa vrednošću null, ...

- Izuzetak je objekat specijane klase koji reprezentuje detalje greške nastale u programu (nosi informacije o uzroku greške, mestu i vremenu nastanka, itd.)

- Generiše se od strane virtuelne mašine (JVM) unutar one metode na mestu na kome nastaje greška

IZUZECI (EXCEPTION)

8 /21

- Svi izuzeci su instance klase Exception ili su nasleđeni iz nje

- Izuzeci koje virtuelna mašina generiše prilikom nastanka greški koje se moraju obraditi zovu se izuzeci sa proverom (checked exceptions)

- Izuzeci koje virtuelna mašina generiše prilikom nastanka greški koje ne se moraju obraditi zovu se izuzeci bez provere (unchecked exceptions), nasleđeni iz klase RuntimeException

TIPOVI IZUZETAKA

9 /21

OBRADA IZUZETAKA KOJI SE PROVERAVAJU

10/21

- Prilikom prevođenja programa prevodilac proverava mogućnost nastajanja greški koje moraju biti obrađene i u skladu sa tim da li je programer predvideo i obradio takve greške u kodu

- Provera i obrada obavljaju se primenom try-catch naredbe:

- Ukoliko se u try bloku ne desi greška, tok se prebacuje na prvu naredbu posle catchbloka: (redosled izvršavanja naredbi je 1, 2, 3, 6)

try {

// blok naredbi u kojima moze nastati greska koja mora biti obradjena

} catch(KlasaIzuzetka e) {

// obrada izuzetka e

}

try {

naredba 1;

naredba 2;

naredba 3;

} catch(KlasaIzuzetka e) {

naredba 4;

naredba 5;

}

naredba 6;

Greška nastala prilikom izvršenja naredbe!Tok izvršavanje prebacuje se na naredbu 4 u catch bloku(redosled izvršavanja naredbi je 1, 2, 4, 5, 6)

tip izuzetka (greške) koji se mora obraditi

PISANJE U TEKSTUALNU DATOTEKU

11/21

- Za pisanje u tekstualnu datoteku koristi se klasa FileWriter (iz paketa java.io)

- Prilikom pisanja, datoteku treba otvoriti (FileWriter konstruktor), pisati po njoj (metoda write() ), i po završetku je zatvoriti (metoda close() )

import java.io.FileWriter; import java.io.IOException;

...

public void snimi(String imeDatoteke){

try{

FileWriter fw = new FileWriter(imeDatoteke)); // otvaranje datoteke

// moguci IOException

fw.write("" + ime.length + “\n"); // pisanje u datoteku (IOException)

for(int i = 0; i < ime.length; i++){

fw.write(ime[i] + ":" + poeni[i] + "\n"); // pisanje (IOException)

}

fw.close(); // zatvaranje datoteke (IOException)

} catch(IOException e){

System.out.println("Greska pri snimanju u " + imeDatoteke);

}

}

blok u kome se izuzetak tipa IOException hvata

oporavak nakon greške

ČITANJE IZ TEKSTUALNE DATOTEKE

12/21

- Za čitanje iz tekstualne datoteke koriste se klase FileReader i BufferedReader

import java.io.FileWriter; import java.io.IOException;

...

public static RangLista ucitaj(String imeDatoteke){

RangLista rl;

try{

BufferedReader r = new BufferedReader(new FileReader(imeDatoteke));

String linija; int i = 0;

rl = new RangLista(Integer.parseInt(r.readLine()));

while( (linija = r.readLine()) != null ) {

String[] x = linija.split(":");

rl.ubaci(i, x[0], Double.parseDouble(x[1]));

i++;

}

r.close();

} catch(FileNotFoundException e) {

System.out.println("Ne postoji datoteka sa imenom " + imeDatoteke);

rl = null;

} catch(IOException e) {

System.out.println("Greska pri citanju " + imeDatoteke);

rl = null;

}

return rl;

}

obrada greške zavisi od tipa izuzetka

otvaranje datoteke

čitanje kraj datoteke?

zatvaranje

- Vreme čitanja sa diska ~ ms, a iz memorije ~ ns (105 - 106 puta sporije u odnosu na mem.)

- Metod read() klase FileReader čita datoteku sa diska karakter po karakter

- Čitanja se ubrzava korišćenjem memorijskog bafera (BufferedReader) koji se jednom operacijom čitanja puni sa diska, a onda iz njega program čita po potrebi

- Kada program učita ceo bafer inicira se njegovo ponovno punjenje

- Metod readLine() klase BufferedReader omogućava čitanje cele linije

KORIŠĆENJE BAFERA ZA ČITANJE

13/21BufferedReader r = new BufferedReader(new FileReader(imeDatoteke));

- Slično kao i pri čitanju iz datoteke sa baferom, realizuje se pomoću BufferedWriter klase

- Bafer se automatski prazni kada se napuni. Poslednji segment ispisa verovatno ne zauzima ceo bafer. Pražnjenje bafera po završetku ispisa obavlja se pri zatvaranju (w.close()) ili na zahtev (w.flush()).

PISANJE U TEKSTUALNU DATOTEKU – KORIŠĆENJE BAFERA

14/21

import java.io.FileWriter; import java.io.IOException;

...

public void snimiV2(String imeDatoteke){

try{

BufferedWriter w = new BufferedWriter( // otvaranje datoteke

new FileWriter(imeDatoteke)); // moguci IOException

w.write("" + ime.length); // pisanje u datoteku (IOException)

w.newLine(); // pisanje u datoteku (IOException)

for(int i = 0; i < ime.length; i++){

w.write(ime[i] + ":" + poeni[i]); // pisanje u datoteku (IOException)

w.newLine(); // pisanje u datoteku (IOException)

}

w.close(); // zatvaranje datoteke i praznjenje bafera (IOException)

} catch(IOException e){

System.out.println("Greska pri snimanju u " + imeDatoteke);

}

}

SAŽIMANJE CATCH BLOKOVA U JEDAN

15/21

- Kada nije potrebno različite izuzetke obradititi na različite načine hvatamo izuzetak klase Exception (princip polimorfne varijable)

import java.io.FileWriter; import java.io.IOException;

...

public static RangLista ucitaj(String imeDatoteke){

RangLista rl;

try{

BufferedReader r = new BufferedReader(new FileReader(imeDatoteke));

String linija; int i = 0;

rl = new RangLista(Integer.parseInt(r.readLine()));

while( (linija = r.readLine()) != null ) {

String[] x = linija.split(":");

rl.ubaci(i, x[0], Double.parseDouble(x[1]));

i++;

}

r.close();

} catch(Exception e) {

// dva izuzetka obradjena na isti nacin

System.out.println(e.getMessage());

rl = null;

}

return rl;

}metod koji vraća sistemskuporuku o greški

- Izuzeci koje virtuelna mašina generiše na greške koje se ne moraju obraditi zovu se izuzeci bez provere (npr., pristup elementu niza van opsega)

- Možemo ih, ali i ne moramo obrađivati kroz try-catch naredbu

- Izuzeci bez provere su objekti nasleđeni iz klase RuntimeException

IZUZECI BEZ PROVERE

16/21

try{

BufferedReader r = new BufferedReader(new FileReader(imeDatoteke));

String linija; int i = 0;

rl = new RangLista(Integer.parseInt(r.readLine()));

while( (linija = r.readLine()) != null ) {

String[] x = linija.split(":");

rl.ubaci(i, x[0], Double.parseDouble(x[1]));

i++;

}

r.close();

} catch(FileNotFoundException e) {

System.out.println("Ne postoji datoteka sa imenom " + imeDatoteke);

rl = null;

} catch(IOException e) {

System.out.println("Greska pri citanju " + imeDatoteke);

rl = null;

}

Šta se dešava ako x[1] ne predstavlja broj?Generiše se NumberFormatException

NumberFormatException se ovde ne obrađuje – program prestaje sa radom uz poruku o greški

- Izuzeci omogućavaju da se spreči kreiranje objekata u nedozvoljenom stanju

- Metoda koja je generisala izuzetak može obraditi izuzetak i izvršiti oporavak na način koji je za dati kontekst najlogičniji

public class RangLista{ // serverska klasa

private String[] ime; // indeks u nizu odnosi se

private double[] poeni; // na mesto u rang listi

public RangLista(int brojMesta){

ime = new String[brojMesta];

poeni = new double[brojMesta];

}

public void ubaci(int rb, String i, double p){

ime[rb - 1] = i; poeni[rb - 1] = p;

}

...

}

IZUZECI BEZ PROVERE

17/21

Šta se dešava ako je brojMesta negativan broj?Generiše se NegativeArraySizeException

double d;

try{ d = Double.parseDouble(x[1]); }

catch(NegativeArraySizeException e){ d = -1; }

- finally blok odrađuje se na kraju try-catch naredbe, bilo da je izuzetak nastao ili ne. Obično se u finally bloku oslobađaju resursi (zatvaranje datoteka, veza ka bazi i sl.)

- Sadržaj finally bloka mogao bi da stoji na istom mestu i bez finally naredbe, pa zašto se onda finally koristi?- Sadržaj finally bloka izvršava se čak i ako se ako se izvrši return u try ili catch blokovima

- Ako se izuzetak desio u try bloku, ali nije uhvaćen, sadržaj finally bloka se opet izvršava

NAREDBA FINALLY

18/21

FileWriter fw = null;

try{

fw = new FileWriter(imeDatoteke));

fw.write("" + ime.length + “\n");

for(int i = 0; i < ime.length; i++){

fw.write(ime[i] + ":" + poeni[i] + "\n");

}

// fw.close(); // prebaceno u finally blok

} catch(IOException e){

System.out.println("Greska pri snimanju u " + imeDatoteke);

} finally{

try { fw.close(); } catch(IOException e1) {}

}

NAREDBA FINALLY

19/21

import java.io.FileWriter; import java.io.IOException;

...

public static RangLista ucitajV3(String imeDatoteke){

RangLista rl;

BufferedReader r = null;

try{

r = new BufferedReader(new FileReader(imeDatoteke));

String linija; int i = 0;

rl = new RangLista(Integer.parseInt(r.readLine()));

while( (linija = r.readLine()) != null ) {

String[] x = linija.split(":");

rl.ubaci(i, x[0], Double.parseDouble(x[1]));

i++;

}

} catch(FileNotFoundException e) {

System.out.println("Ne postoji datoteka sa imenom " + imeDatoteke);

rl = null;

} catch(IOException e) {

System.out.println("Greska pri citanju " + imeDatoteke);

rl = null;

} finally { try{ r.close(); } catch(IOException e){} }

return rl;

}

Ako se desi izuzetak koji nijeuhvaćen, opet se pre prekida programa izvršava finally blok(NumberFormatException)

- Ukoliko se ne obrade unutar metode M na mestu gde nastaju, izuzeci se mogu proslediti iz M u pozivajuću metodu da ih ona obradi

- Prosleđivanje se vrši onda kada metoda nema dovoljno informacija da obradi izuzetak

- Prosleđivanje može da se proteže kroz više nivoa

PROSLEĐIVANJE IZUZETAKA – THROWS NAREDBA

20/21

public void snimiV4(String imeDatoteke) throws IOException {

FileWriter fw = new FileWriter(imeDatoteke);

fw.write("" + ime.length + "\n");

for(int i = 0; i < ime.length; i++){

fw.write(ime[i] + ":" + poeni[i] + "\n");

}

fw.close();

}public static void testSnimiV4(){

RangLista rl = new RangLista(10);

rl.ubaci(1, "Pera Perin", 100);

rl.ubaci(2, "Mika Mikic", 90);

try{

rl.snimiV4("/test/rlista.txt");

} catch(IOException e){

System.out.println("Problem pri snimanju");

}

}

Metoda snimiV4 prosleđuje izuzetak u metodu testSnimiV4

- Ulaz sa tastature se može čitati na različite načine, ali se najčešće koristi klasa scaner iz paketa java.util

- Pogledati samostalno dokumentaciju u java.api

ČITANJE SA TASTATURE – KLASA SCANER

21/21


Recommended