1. Języki Java, C# 2. Program w Javie (aplikacja, aplet) 3. Typy danych, zmienne i stałe 4. Operatory 5. Instrukcje sterujące 6. Obsługa wyjątków 1.1 Języki Java i C# Java i C# to dalszy "etap rozwoju" języka C++. Są to języki w pełni obiektowe, zasadniczo o interpretowanym kodzie, ze zintegrowaną biblioteką klas dla programowania zdarzeniowego, wielowątkowego, tworzenia GUI, obiektowej komunikacji rozproszonej, i innych. Główny cel powstania: uniwersalny (niezaleŝny od sprzętu) język programowania tzw. systemów "wbudowanych" (ang. embedded systems ) (do róŝnorodnych zastosowań - sterowania robotem, pralką, telefonia komórkowa, itd). Uniwersalność kodu uzyskano dzięki stworzeniu zaleŝnej od sprzętu (pośredniej) warstwy oprogramowania ( abstrakcyjnej maszyny ) (ang. Java Virtual Machine, C# MSIL). Ta "maszyna" interpretuje kod pośredni programu Javy wzgl. C#. Java szybko znalazła zastosowanie w programowaniu internetowym. RównieŜ C#.NET posiada juŝ tę funkcjonalność. W. Kasprzak: Programowanie zdarzeniowe 1-2
Zabezpieczenia zawarte w Javie poprawiły bezpieczeństwo dokumentów w Internecie. Zasadnicze cechy języka Java wzgl. C#: obiektowość - język zaprojektowany od początku jako obiektowy, notacja podobna do C/C++, obsługa sytuacji wyjątkowych - rozbudowana kontrola w czasie kompilacji i wykonania, pełnoprawny typ referencyjny - brak wskaźników, bardzo ograniczona niejawna konwersja typów danych; przenaszalność język pośredni - ścisła definicja wbudowanych typów danych, obiektowe programowanie wielowątkowe, wbudowane narzędzia programowania zdarzeniowego - z biblioteką graficzną dla GUI, program sterowany zdarzeniami. W. Kasprzak: Programowanie zdarzeniowe 1-3 1.2 Program w Javie Bajtkod Javy - to instrukcje dla maszyny wirtualnej (JavaVM). W. Kasprzak: Programowanie zdarzeniowe 1-4
Platforma programowa Javy: Wirtualna maszyna Javy (Java VM) Interfejs programisty uŝytkowego (Java API) Java API: zbiór elementów programowych o szerokiej funkcjonalności (np. komponenty GUI, JDBC); pogrupowanych w biblioteki klas i interfejsów (tzw. pakiety). Java API i Java VM separują program od sprzętu: W. Kasprzak: Programowanie zdarzeniowe 1-5 KaŜda pełna implementacja platformy Java posiada: Język: obiekty, string, typy liczbowe, wątki, wejście I wyjście, struktury danych, systemowe własności, data i czas, itd. Aplety: konwencje stosowane przez aplety; API dla grafiki 2W i 3W, animacji, mowy, telefonii, itp. Sieciowe: URL, TCP (Transmission Control Protocol), UDP (User Datagram Protocol) gniazdka, adresy IP (Internet Protocol). Internacjonalizacja: automatyczne dostosowanie do regionu świata; Zabezpieczenia: podpis elektroniczny, klucze publiczne i prywatne, kontrola dostępu, certyfikaty. Komponenty programowe: JavaBeans; Serializacja i komunikacja obiektów: umoŝliwia trwałość obiektów i komunikację poprzez mechanizm Remote Method Invocation (RMI). Komunikacja z bazami danych - Java Database Connectivity (JDBC): W. Kasprzak: Programowanie zdarzeniowe 1-6
Środowisko programisty np. Sun J2SE 5.0: zawiera JRE ( Java 2 Runtime Environment ) (maszyna wirtualna Javy, główna hierarchia klas i pliki pomocnicze); i narzędzia do tworzenia programów kompilatory, debagery; W. Kasprzak: Programowanie zdarzeniowe 1-7 Kompilator w locie - Just-in-Time (JIT) - tłumaczy kod pośredni Javy na kod maszynowy podczas wykonania kodu. W. Kasprzak: Programowanie zdarzeniowe 1-8
Przykład 1.1 Aplikacja "HelloWorld": /** * Wyświetla napis "Hello World!" na standardowym wyjściu. */ public class HelloWorldApp { public static void main(string[ ] args) { System.out.println("Hello World!"); // Komentarze /** komentarz */ - ten komentarz wykorzysta javadoc tworząc dokumentację // komentarz - komentarz do końca wiersza /* komentarz */ komentarz przez wiele wierszy Metoda main - jest to punkt wejścia do programu Javy. W. Kasprzak: Programowanie zdarzeniowe 1-9 Wywołanie kompilatora: javac HelloWorldApp.java Kompilator generuje plik z kodem pośrednim: HelloWorldApp.class Wykonanie aplikacji: java HelloWorldApp Przykład 1.2. Aplet "Hello World" import java.applet.*; import java.awt.*; /** Klasa HelloWorld implementuje aplet który * wyświetla napis "Hello World!". */ public class HelloWorld extends Applet { public void paint(graphics g) { g.drawstring("hello world!", 50, 25); Utworzymy podany kod w pliku HelloWorld.java. W. Kasprzak: Programowanie zdarzeniowe 1-10
Potrzebny nam jest odpowiedni plik HTML o nazwie Hello.html: <HTML> <HEAD><TITLE> Pierwszy Program</TITLE> </HEAD> <BODY> <APPLET CODE="HelloWorld.class" WIDTH=150 HEIGHT=25> </APPLET> </BODY> </HTML> Kompilacja pliku źródłowego: javac HelloWorld.java Uruchamiamy aplet wywołując przeglądarkę lub appletviewer : appletviewer Hello.html Instrukcja import (dołącz klasy lub pakiety): import java.applet.applet; // importuj klasę import java.awt.graphics; // importuj klasę public class HelloWorld extends Applet { public void paint(graphics g) { g.drawstring("hello world!", 50, 25); W. Kasprzak: Programowanie zdarzeniowe 1-11 Alternatywna postać bez instrukcji "import": public class HelloWorld extends java.applet.applet { public void paint (java.awt.graphics g) { g.drawstring("hello world!", 50, 25); Dzięki "import" moŝemy odwoływać się do klas "Applet" i "Graphics" bez przedrostków (podając ich proste nazwy). java.applet i java.awt to pakiety zawarte w Java API; java.applet zawiera klasy istotne dla działania apletów; java.awt - klasy z "Abstract Window Toolkit" (AWT) dla tworzenia GUI. Klasa System zawarta jest w pakiecie java.lang, automatycznie importowanym do kaŝdego programu w Java. W. Kasprzak: Programowanie zdarzeniowe 1-12
Importowanie pakietu: import java.applet.*; // importuj pakiet import java.awt.*; // importuj pakiet public class HelloWorld extends Applet { public void paint(graphics g) { g.drawstring("hello world!", 50, 25); - KaŜda klasa naleŝy do jakiegoś pakietu. Jeśli plik z definicją klasy nie deklaruje na górze do którego pakietu klasa naleŝy, to naleŝy ona do "domyślnego" pakietu. - Klasy naleŝące do tego samego pakietu mogą odwoływać się do siebie bez konieczności stosowania nazw kwalifikowanych (bez przedrostka). W. Kasprzak: Programowanie zdarzeniowe 1-13 Definicja klasy pochodnej od Applet import java.applet.applet; import java.awt.graphics; public class HelloWorld extends Applet { // Początek definicji klasy public void paint(graphics g) { g.drawstring("hello world!", 50, 25); extends wskazuje, Ŝe HelloWorld jest klasą pochodną klasy Applet. Implementacja metod klasy Applet import java.applet.applet; import java.awt.graphics; public class HelloWorld extends Applet { public void paint(graphics g) { // Implementacja metody paint g.drawstring("hello world!", 50, 25); W. Kasprzak: Programowanie zdarzeniowe 1-14
KaŜdy aplet musi implementować jedną lub więcej z metod: init, start, paint. Poza tym aplety mogą implementować metody: stop, destroy (przeznaczone do zakończenia współpracy strony z apletem), a takŝe szereg innych metod. Obiekt klasy Graphics reprezentuje kontekst ekranu dla pracy metody paint naszego apletu: pierwszy argument podaje tekst do wyświetlenia, argumenty (x,y) podają pozycję lewego dolnego rogu tekstu na ekranie w układzie współrzędnych kontekstu graficznego g. W. Kasprzak: Programowanie zdarzeniowe 1-15 Wywołanie apletu <HTML> <HEAD> <TITLE> Prosty program </TITLE> </HEAD> <BODY> <APPLET CODE="HelloWorld.class" WIDTH=150 HEIGHT=25> </APPLET> </BODY> </HTML> Blok <APPLET> podaje nazwę apletu HelloWorld.class, związuje z nim kontekst graficzny - jego pozycję i rozmiary na ekranie. Przeglądarka przeszukuje katalog z plikiem.html, załadowuje plik z klasą apletu przez sieć na własny komputer i tworzy instancję klasy. Atrybuty WIDTH i HEIGHT podają szerokość i wysokość w pikselach obszaru graficznego związanego z apletem na ekranie. W. Kasprzak: Programowanie zdarzeniowe 1-16
1.3 Typy danych, zmienne i stałe Typy danych w Javie dzielimy na: typy wbudowane i typy tworzone (definiowane) przez programistę klasy, typy przeliczeniowe ("enum"). Wbudowane typy danych: (1) Typy dla wartości - ("value-type") - typy proste: zmienne tych typów posiadają wartości tych samych typów. (2) Typy referencyjne: zmienne tych typów referują tablice lub obiekty klas; wartością zmiennej jest odniesienie do tablicy lub obiektu. W. Kasprzak: Programowanie zdarzeniowe 1-17 Wbudowane typy proste: Nazwa Opis Format (całkowite) byte Byte integer 8-bitowy kod U2 short Short integer 16-bitowy kod U2 int Integer 32-bitowy kod U2 long Long integer 64-bitowy kod U2 (zmiennoprzecinkowe) float Single-precision 32-bit IEEE 754 double Double-precision 64-bit IEEE 754 (inne) char Pojedynczy znak 16-bitowy znak Unikodu boolean Wartość logiczna true, false W. Kasprzak: Programowanie zdarzeniowe 1-18
Zmienna to jednostka danych przechowująca stan (wielkość) określonego typu, ma przyporządkowane miejsce pamięci i opatrzona jest nazwą (identyfikatorem zmiennej). Ze zmienną związane są: Typ (wyznacza rodzaj danych i operacji na nich) Nazwa (sekwencja znaków Unikodu), Wartość (aktualny stan obiektu); Zasięg definicji (zakres widoczności) (zakres programu w którym odwołujemy się do zmiennej poprzez jej prostą nazwę); Czas Ŝycia. Aby nadać zmiennej typ i nazwę wykonujemy instrukcję definicji: typ nazwa Pierwszą wartość zmiennej nadaje się podczas definicji połączonej z inicjalizacją lub w wyniku instrukcji przypisania. Wartości mogą być zmienianie w wyniku instrukcji przypisania. W. Kasprzak: Programowanie zdarzeniowe 1-19 Przykład 1.3. Definicje 8 zmiennych. public class MaxVariablesDemo { public static void main (String args[]) { // typy całkowite byte largestbyte = Byte.MAX_VALUE; short largestshort = Short.MAX_VALUE; int largestinteger = Integer.MAX_VALUE; long largestlong = Long.MAX_VALUE; // typy zmienno-przecinkowe (podzakres liczb rzeczywistych) float largestfloat = Float.MAX_VALUE; double largestdouble = Double.MAX_VALUE; // inne typy char achar = 'S'; boolean aboolean = true; //... W. Kasprzak: Programowanie zdarzeniowe 1-20
Uwagi: MAX_VALUE to stałe zdefiniowane w osobnych klasach liczb. Największa liczba typu byte to 127 Największa liczba typu short to 32767 Największa liczba typu integer to 2147483647 Największa liczba typu long to 9223372036854775807 Największa liczba typu float to 3.40282e+38 Największa liczba typu double to 1.79769e+308 W. Kasprzak: Programowanie zdarzeniowe 1-21 Stałe (literały, stałe symboliczne) : - przeznaczone do inicjalizacji zmiennych; - kaŝda stała posiada typ i wartość. Literał (stała bez nazwy) - typ danych wynika niejawnie ze sposobu zapisu. Przykład 1.4. Przykłady literałów i ich typów: Literal Typ danych 178 int 8864L long 37.266 double 37.266D double 87.363F float 26.77e3 double ' c ' char true boolean false boolean W. Kasprzak: Programowanie zdarzeniowe 1-22
Stałe symboliczne - to stałe opatrzone nazwą i jawnym typem. Definicja stałej symbolicznej: final typ NAZWASTALEJ = wartość; Np. final float PI = 3.141592; final int MAXSIZE = 40000; final PersonalDB DIAPERS = new PersonalDB(); Konwencja: w nazwach stałych symbolicznych stosujemy duŝe litery. Lokalną stałą symboliczną moŝna zainicjować później - najpierw sama deklaracja a później przypisanie pierwszej (i ostatecznej) wartości. Np. final int STAŁA_CZYSTA; // Deklaracja tzw. "czystej" stałej... STAŁA_CZYSTA = 0; // Inicjalizacja czystej stałej W. Kasprzak: Programowanie zdarzeniowe 1-23 Referencja to dana, której wartością jest adres. Typy referencyjne: tablice, klasy, interfejsy. Zmienna referencyjna odnosi się do miejsca pamięci, w którym pomieszczono daną lub wektor danych reprezentowanych tą zmienną. Nie ma typu wskaźnikowego, tzn. jawnego korzystania z adresów. Prosta nazwa zmiennej składa się z pojedynczego identyfikatora. Kwalifikowana nazwa zmiennej zawiera więcej niŝ jeden identyfikator. Identyfikator (nazwa) zmiennej: 1. Nieograniczony ciąg znaków Unikodu rozpoczynający się od litery; 2. Nie będący słowem kluczowym ani teŝ: true, false, null. 3. Unikalny w swoim zasięgu interpretacji nazw. W. Kasprzak: Programowanie zdarzeniowe 1-24
Konwencja: - nazwa zmiennej rozpoczyna się małą literą, ale nazwa klasy - duŝą; - drugie słowo w nazwie rozpoczyna się juŝ duŝą literą, np. isvisible; - znak podkreślenia (_) jest wprawdzie poprawny w nazwie, ale powinien być uŝywany jedynie w nazwach stałych (tam są wyłącznie duŝe litery). Zasięg zmiennej - obszar programu, w którym do zmiennej odwoływać się moŝemy poprzez jej nazwę - wyznacza teŝ czas Ŝycia zmiennej. Inicjalizacja zmiennych wg kategorii ich zasięgów: Lokalna zmienna i składowa klasy mogą być inicjowane w miejscu deklaracji. Parametery metod i obsługi wyjątków są inicjowane w procesie wywołania tych metod wzgl. procedur obsługi wyjątków. W. Kasprzak: Programowanie zdarzeniowe 1-25 Kategorie zasięgu (zakresu interpretacji) zmiennej: Zasięgi: składowej klasy parametru metody, lokalnej zmiennej parametru obsługi wyjątków W. Kasprzak: Programowanie zdarzeniowe 1-26
1.4 Operatory Operator - operacja (funkcja) podana w notacji operatorowej - z 1, 2 lub 3 argumentami (operandami). Jedyny operator 3-arg. to:?: 1-argumentowe operatory mogą być przedrostkowe i przyrostkowe: operator operand // Notacja przedrostkowa operand operator // Notacja przyrostkowa 2-argumentowe operatory występują pomiędzy swoimi operandami. operand1 operator operand2 // 3-argumentowy operator: operand1? operand2 : operand3 // Operatory arytmetyczne Za wyjątkiem operatora + uŝywanego teŝ do łączenia napisów operatory arytmetyczne są przeznaczone tylko dla liczbowych danych. W. Kasprzak: Programowanie zdarzeniowe 1-27 Operator WyraŜenie Opis + op1 + op2 dodawanie op1 i op2 - op1 - op2 odejmowanie op2 od op1 * op1 * op2 mnoŝenie op1 przez op2 / op1 / op2 dzielenie op1 przez op2 % op1 % op2 reszta z dzielenia op1 przez op2 Operator zwraca wynik określonego typu. Gdy typy operandów są róŝne konwersja niejawne (poszerzanie typu) podczas obliczania wyraŝeń: Typ wyniku Typy argumentów: long nie są typu float ani double; co najmniej jeden jest typu long int nie są typu float ani double; Ŝaden nie jest typu long double co najmniej jeden jest typu double float co najmniej jeden jest typu float; Ŝaden nie jest double W. Kasprzak: Programowanie zdarzeniowe 1-28
1-argumentowe wersje operatorów + i - : Operator WyraŜenie Opis + +op Poszerza op do int jeśli op jest typu byte,short,char. - -op Arytmetyczna negacja op. Przed- i przyrostkowe operatory ++ i --. przedrostkowe ++op, --op : zwróć wartośc operanda po operacji; przyrostkowe op++, op--: zwróć wartość operanda sprzed operacji. Operatory porównań (relacji) Operator WyraŜenie Wynik jest "true" gdy: > op1 > op2 op1 większe niŝ op2 >= op1 >= op2 op1 większe lub równe op2 < op1 < op2 op1 mniejsze niŝ op2 <= op1 <= op2 op1 mniejsze lub równe op2 == op1 == op2 op1 i op2 są równel!= op1!= op2 op1 i op2 są nierówne W. Kasprzak: Programowanie zdarzeniowe 1-29 Operatory logiczne (dla argumentów typu boolean) Operator WyraŜenie Wynik jest "true" gdy: && op1 && op2 op1 i op2 są prawdziwe op1 op2 op1 lub op2 jest prawdziwe!! op op jest fałszywe & op1 & op2 op1 i op2 są prawdziwe op1 op2 op1 lub op2 jest prawdziwe ^ op1 ^ op2 op1 i op2 są róŝne Uwaga: 0 <= index && index < NUM_ENTRIES Gdy pierwszy operand zostanie obliczony jako false, drugi operand nie będzie juŝ interpretowany, gdyŝ wynik i tak będzie false. W. Kasprzak: Programowanie zdarzeniowe 1-30
Operatory bitowe przesunięć Operator WyraŜenie Operacja >> op1 >> op2 przesuń op1 w prawo o op2 bitów (zachowuje znak liczby) << op1 << op2 przesuń op1 w lewo o op2 bitów >>> op1 >>> op2 przesuń op1 w prawo o op2 bitów z wypełnieniem zerami (liczba bez znaku) Operatory bitowe logiczne Operator WyraŜenie Operacja & op1 & op2 bitowe AND op1 op2 bitowe OR ^ op1 ^ op2 bitowe XOR ~ ~op2 bitowa negacja W. Kasprzak: Programowanie zdarzeniowe 1-31 Operatory przypisania Podstawowy = : op1 = op2 Rozszerzone operatory przypisania: Operator WyraŜenie RównowaŜne z: += op1 += op2 op1 = op1 + op2 -= op1 -= op2 op1 = op1 - op2 *= op1 *= op2 op1 = op1 * op2 /= op1 /= op2 op1 = op1 / op2 %= op1 %= op2 op1 = op1 % op2 &= op1 &= op2 op1 = op1 & op2 = op1 = op2 op1 = op1 op2 ^= op1 ^= op2 op1 = op1 ^ op2 <<= op1 <<= op2 op1 = op1 << op2 >>= op1 >>= op2 op1 = op1 >> op2 >>>= op1 >>>= op2 op1 = op1 >>> op2 W. Kasprzak: Programowanie zdarzeniowe 1-32
Inne operatory Operator WyraŜenie Opis?: op1? op2 : op3 gdy op1 jest "true" zwraca op2, w przeciwnym razie zwraca op3 [] typ [] Deklaracja tablicy elementów typu typ. [] typ[ op1 ] Utworzenie tablicy o liczbie op1 elementów typu typ operatorem new. [] op1[ op2 ] Pobranie elementu o indeksie op2 w tablicy op1.. op1.op2 Odwołanie do składowej op2 z op1. () op1(param) Deklaracja lub wywołanie metody op1 z listą parametrów (argumentów) param. (typ) (typ) op1 Konwersja wyraŝenia op1 do typu typ. new new op1 Utworzenie obiektu lub tablicy. instanceof op1 instanceof Zwraca "true" gdy obiekt op1 jest op2 instancją klasy op2 W. Kasprzak: Programowanie zdarzeniowe 1-33 Tabela operatorów według priorytetów - im wyŝej połoŝony wiersz tym wyŝszy priorytet: Przyrostkowe operatory []. (param) wyraŝ++ wyraŝ-- 1-arg. operatory ++wyraŝ --wyraŝ +wyraŝ -wyraŝ ~! Konstrukcja, konwersja new (typ)wyraŝ Arytm. multiplikatywne * / % Arytm. addytywne + - Przesunięć < Porównania < > <= >= instanceof Porówn. równościowe ==!= Bitowe AND & Bitowe exclusive OR ^ Bitowe OR Logiczne AND && Logiczne OR Warunkowy? : Przypisania = += -= *= /= %= &= ^= = <<= >>= >>>= W. Kasprzak: Programowanie zdarzeniowe 1-34
1.5 Instrukcje sterujące UmoŜliwiają zmianę sekwencyjnego sposobu wykonania programu. Rodzaj instrukcji pętla warunek obsługa wyjątku skok Slowa kluczowe while, do-while, for if-else, switch-case try-catch-finally, throw break, continue, etykieta:, return while (wyraŝenie) { instrukcje // Wykonuj petlę gdy wyraŝenie jest prawdziwe ( true). do { instrukcje while (wyraŝenie); // Sprawdzenie warunku następuje po zakończeniu pętli. W. Kasprzak: Programowanie zdarzeniowe 1-35 for (inicjalizacja; warunek; inkrementacja) { instrukcje // Wszystkie trzy wyraŝenia są opcjonalne: // MoŜe być: for( ; ; ) if (wyraŝenie) { instrukcje W. Kasprzak: Programowanie zdarzeniowe 1-36 if ( flaga == OK) { // akcja "OK." else { // akcja "Cancel" switch (miesiąc) { case 1: System.out.println("Styczeń"); break; //... case 12: System.out.println("Grudzień"); break; default: System.out.println("Błędny miesiąc!"); break;
Obsługa sytuacji wyjątkowych try { instrukcje // tu moŝe wystąpić throw catch (typ_wyjątku nazwa) { // obsługa wyjątku danego typu instrukcje finally { // wykonywana zawsze niezaleŝnie od wyjątku instrukcje Instrukcje skoków - Etykietowana instrukcja: etykietainstrukcji: pewnainstrukcja; - Instrukcja break bez etykiety - kończy wykonywanie aktualnej wewnętrznej instrukcji sterującej: switch, for, while, do-while. break; W. Kasprzak: Programowanie zdarzeniowe 1-37 - Instrukcja break z etykietą - kończy wykonywanie zewnętrznego switch, for, while, do-while o podanej etykiecie: break etykietainstrukcji; - Instrukcja continue kończy bieŝącą iterację wewnętrznej pętli : continue; - Instrukcja continue z etykietą kończy bieŝącą iterację zewnętrznej instrukcji pętli o podanej etykiecie: continue etykietainstrukcji; - Instrukcja return - powrót z wykonywanej metody. return wyraŝenie; // Typ wyniku musi odpowiadać deklaracji. return; // W metodzie o wyniku typu void W. Kasprzak: Programowanie zdarzeniowe 1-38
1.6 Obsługa sytuacji wyjątkowych Wyjątek - przerwanie normalnego wykonania programu, na skutek jakiegoś błędu lub nadzwyczajnej sytuacji w programie. Np.: błąd działania sprzętu, brak wystarczającej pamięci, brak dostępu do zasobów, itp. Zalety stosowania mechanizmu obsługi sytuacji wyjątkowych. 1. Oddzielenie kodu obsługi błędu od "normalnego kodu" Np. mamy normalny pseudo-kod wykonania: void readfile { otwórz plik; określ rozmiar pliku; alokuj pamięci odpowiednio do rozmiaru pliku; wczytaj plik do pamięci; zamknij plik; Teraz naleŝy uwzględnić moŝliwe błędy programu. Dojdziemy do pewnego pseudo-kodu z wymieszanym "normalnym kodem" i W. Kasprzak: Programowanie zdarzeniowe 1-39 "sprawdzaniem błędów": errorcodetype readfile { errorcode = 0; otwórz plik; if (plikjestotwarty) { określ rozmiar pliku; if (mamrozmiarpliku) { alokuj pamięć o rozmiarze pliku; if (jestwystarczającapamięc) { wczytaj plik do pamięci; if (odczytbłędny) { errorcode = -1; else { errorcode = -2; else { errorcode = -3; zamknij plik; if (plikniezamykasię) { errorcode = -4; else { errorcode = -5; return errorcode; Oryginalny przepływ programu nie jest juŝ widoczny w nowym kodzie. Wykorzystując mechanizm obsługi wyjątków nasz pseudo-kod wyglądać W. Kasprzak: Programowanie zdarzeniowe 1-40
będzie duŝo czytelniej: void readfile { try { otwórz plik; określ rozmiar pliku; alokuj pamięci odpowiednio do rozmiaru pliku; wczytaj plik do pamięci; zamknij plik; catch (PlikNieotwarty) { obsłuŝpliknieotwarty; catch (BrakRozmiaru) { obsłuŝbrakrozmiaru; catch (BrakPamięci) { obsłuŝbrakpamięci; catch (OdczytNieudany) { obsłuŝodczytnieudany; catch (PlikNiezamkniety) { obsłuŝplikniezamkniety; 2. MoŜliwość kontrolowanego propagowania błędów przez hierarchię wywołań Np. mamy wywołania: metoda 1 woła metodę 2 ta metodę 3 a ta readfile. Niech jedynie metoda 1 jest zainteresowana błędami W. Kasprzak: Programowanie zdarzeniowe 1-41 powstałymi podczas wykonania readfile. W normalnym kodzie propagacje błędu wstecz musiałyby być jawnie rozpatrywane w kodzie: void metoda1() { errorcodetype error; error = metoda2(); if (error) obsłuŝbłąd; else kontynuuj; errorcodetype metoda2() { errorcodetype error; error = metoda3(); if (error) return error; else kontynuuj; errorcodetype metoda3() { errorcodetype error; error = readfile(); W. Kasprzak: Programowanie zdarzeniowe 1-42
if (error) return error; else kontynuuj; System obsługi wyjątków umoŝliwia automatyczny powrót do miejsca, w którym odbędzie się rozpoznanie i obsługa wyjątku: void metoda1() { try { metoda2(); catch (wyjatek) { obslugabłedu; void metoda2() throws wyjatek { metoda3(); void metoda3() throws wyjatek { readfile(); Zaleta 3. Grupowanie błędów i ich obsługi. W Javie wszystkie zgłaszane wyjątki są obiektami klas: obiektem klasy Throwable lub jej klasy pochodnej. W. Kasprzak: Programowanie zdarzeniowe 1-43 Sprawdzalne wyjątki Java wymaga aby metody obsługiwały lub specyfikowały wszystkie sprawdzalne wyjątki, które mogą wystąpić podczas wykonania metody. Wyjątki, które są typowe dla środowiska czasu wykonania, nie są sprawdzalne przez kompilator. Nie ma wymogu ich obsługi lub deklarowania ich wystąpienia. Np. są nimi: wyjątki arytmetyczne (np. dzielenie przez zero), wyjątki wskazań (np. próba odwołania do obiektu poprzez zerową referencję), wyjątki indeksowania (np. odwołanie do elementu tablicy poprzez zły indeks). Sprawdzane wyjątki to takie, których obsługę lub deklarowanie sprawdza kompilator. Przykład 1.5 Klasa InputFile obejmuje FileReader i posiada metodę getword, dla odczytu słowa z obiektu odczytywanego (tzw. reader). import java.io.*; public class InputFile { W. Kasprzak: Programowanie zdarzeniowe 1-44
private FileReader in; public InputFile(String filename) { in = new FileReader(filename); public String getword() { int c; StringBuffer buf = new StringBuffer(); do { c = in.read(); if (Character.isWhitespace((char)c)) return buf.tostring(); else while (c!= -1); return buf.tostring(); buf.append((char)c); Program ignoruje moŝliwość zgłoszenia wyjątku przez konstruktor FileReader() jak teŝ metodę read(). Kompilator zgłosi dwa błędy: InputFile.java:4: Warning: Exception java.io.filenotfoundexception W. Kasprzak: Programowanie zdarzeniowe 1-45 must be caught, or it must be declared in throws clause of this method. in = new FileReader(filename); InputFile.java:9: Warning: Exception java.io.ioexception must be caught, or it must be declared in throws clause of this method. c = in.read(); W. Kasprzak: Programowanie zdarzeniowe 1-46
Obsługa wyjątków Przykład 1.6. Nasza klasa ListOfNumber wywołuje dwie metody klas Javy, które mogą zgłaszać wyjątki. // Uwaga: Ten program nie skompiluje się! import java.io.*; import java.util.vector; public class ListOfNumbers { private Vector victor; private static final int size = 10; public ListOfNumbers () { victor = new Vector(size); for (int i = 0; i < size; i++) victor.addelement( new Integer(i)); public void writelist() { PrintWriter out = new PrintWriter ( new FileWriter("OutFile.txt")); W. Kasprzak: Programowanie zdarzeniowe 1-47 for (int i = 0; i < size; i++) out.println("value at: " + i + " = " + victor.elementat(i)); out.close(); Metoda writelist wywołuje dwie metody, które mogą zgłaszać wyjątki: konstruktor klasy FileWriter zgłosi IOException, jeśli nie moŝna otworzyć podanego pliku: out = new PrintWriter(new FileWriter("OutFile.txt")); metoda elementat klasy Vector zgłosi ArrayIndexOutOfBoundsException, jeśli przekazany jej indeks jest poza zakresem elementów obiektu klasy Vector: out.println("value at: " + i + " = " + victor.elementat(i)); Kompilator sprawdza tylko istnienie obsługi lub deklaracji wyjątku IOException, ale nie sprawdza wyjątku czasu wykonania - ArrayIndexOutOfBoundsException. W. Kasprzak: Programowanie zdarzeniowe 1-48
Blok try Kod metody writelist ujmiemy w blok try - aktywacji śledzenia wyjątków: PrintWriter out = null; try { System.out.println("Początek bloku try"); out = new PrintWriter( new FileWriter("OutFile.txt")); for (int i = 0; i < size; i++) out.println("value at: " + i + " = " + victor.elementat(i)); Po bloku try musi wystąpić przynajmniej jeden blok catch lub blok finally. Np. try {... catch (ArrayIndexOutOfBoundsException e) { W. Kasprzak: Programowanie zdarzeniowe 1-49 System.err.println("Wyjątek: ArrayIndexOutOfBoundsException: " + e.getmessage()); catch (IOException e) { System.err.println("Wyjątek: IOException: " + e.getmessage()); Obsługa wyjątków typu klasy bazowej moŝe obsłuŝyć teŝ wyjątki typu klas pochodnych. Np.: try {... catch (Exception e) { System.err.println("ObsłuŜono: " + e.getmessage()); Teraz w jednym bloku ogólnym obsłuŝymy wyjątki IOException i ArrayIndexOutOfBoundsException, ale tez szereg dalszych. W. Kasprzak: Programowanie zdarzeniowe 1-50
Blok finally UmoŜliwia kontrolowane "opuszczenie" fragmentu programu, niezaleŝnie od tego czy w bloku try wystąpił wyjątek, czy teŝ nie. Np. w naszym przykładzie 1.6 stosujemy blok finally w metodzie writelist dla zamknięcia obiektu PrintWriter. finally { if (out!= null) { System.out.println("Zamykanie PrintWriter"); out.close(); else { System.out.println("PrintWriter nie jest otwarty"); Korzyść z bloku try - oddzielenie fragmentu planowego zwalniania zasobów programu od normalnego kodu, wykonanie tego fragmentu niezaleŝnie od tego, czy wystąpił błąd czy tez nie. Np. bez bloku try musielibyśmy stworzyć we writelist następujący kod: try {... out.close(); // kod ten będzie powtórzony poniŝej W. Kasprzak: Programowanie zdarzeniowe 1-51 catch (ArrayIndexOutOfBoundsException e) { out.close(); // powtórzenie kodu System.err.println("ObsłuŜono: ArrayIndexOutOfBoundsException: " + e.getmessage()); catch (IOException e) { System.err.println("ObsłuŜono IOException: " + e.getmessage()); Przykład 1.7. Cała metoda writelist() po modyfikacjach potrzebnych dla obsługi wyjątków wygląda teraz następująco: public void writelist() { PrintWriter out = null; try { System.out.println("Początek bloku try"); out = new PrintWriter( new FileWriter("OutFile.txt")); for (int i = 0; i < size; i++) out.println("value at: " + i + " = " + victor.elementat(i)); W. Kasprzak: Programowanie zdarzeniowe 1-52
catch (ArrayIndexOutOfBoundsException e) { System.err.println("Obsługa: ArrayIndexOutOfBoundsException:" + e.getmessage()); catch (IOException e) { System.err.println("ObsłuŜono: IOException: " + e.getmessage()); finally { if (out!= null) { System.out.println("Zaykanie PrintWriter"); out.close(); else { System.out.println("PrintWriter nie jest otwarty"); Uwagi: 1. Jeśli metoda writellist nie posiadałyby bloku catch obsługującego sprawdzalny wyjątek IOException, to naleŝałoby zadeklarować go w liście wyjątków tej metody, np.: W. Kasprzak: Programowanie zdarzeniowe 1-53 public void writelist() throws IOException, ArrayIndexOutOfBoundsException { 2. Wyjątek ArrayIndexOutofBoundsException nie jest sprawdzalny przez kompilator i nie musi być tu deklarowany. Zgłaszanie wyjątków throw pewienthrowableobject; Jako wyjątek moŝe być zgłoszony jedynie obiekt klasy Throwable lub klasy pochodnej od Throwable. W innym razie wystąpi błąd kompilacji: testing.java:10: Cannot throw class java.lang.integer; it must be a subclass of class java.lang.throwable. throw new Integer(4); ^ Np. public Object pop() throws EmptyStackException { Object obj; if (size == 0) throw new EmptyStackException(); W. Kasprzak: Programowanie zdarzeniowe 1-54
obj = objectat(size - 1); setobjectat(size - 1, null); size--; return obj; Hierarchia klas wyjątków Error. Błąd dynamicznej konsolidacji programu lub inny "cięŝki" błąd w JVM. Programy w Javie nie powinny obsługiwać ani zgłaszać takich wyjątków. Exception. To jest klasa bazowa wyjątków w programach Javy. Są juŝ W. Kasprzak: Programowanie zdarzeniowe 1-55 liczne klasy pochodne tej klasy, np. IllegalAccessException, NegativeArraySizeException. Runtime Exception Specialna klasa pochodna od Exception, która dotyczy wyjątków zgłaszanych w Java virtual machine (czyli podczas wykonania programu). Np. NullPointerException. Tworzenie własnych klas wyjątków Dla naszej klasy powinniśmy utworzyć klasy ewentualnych wyjątków, które mogą być zgłaszane w jej metodach. Nasz główna klasa wyjątków powinna dziedziczyć z klasy Exception. Dziedziczenie z klasy RuntimeException, mimo iŝ kusi brakiem konieczności deklarowania wyjątków w metodach, powinniśmy zostawić środowisku czasu wykonania, czyli JVM. Konwencja - nazwy klas dziedziczących z Exception kończą się na "Exception". W. Kasprzak: Programowanie zdarzeniowe 1-56