Wyjątki, rzutowanie, operator instanceof

Post on 21-Jan-2016

43 views 0 download

description

Wyjątki, rzutowanie, operator instanceof. Kamil Piekarz Inforamtyka II rok, grupa V prowadzący zajęcia mgr. inż. Dominik Radziszowski. Wyjątki. W czasie wykonania programu mogą wystąpić różne rodzaje błędów:. - PowerPoint PPT Presentation

Transcript of Wyjątki, rzutowanie, operator instanceof

Wyjątki, rzutowanie,

operator instanceof

Kamil PiekarzInforamtyka II rok, grupa V

prowadzący zajęciamgr. inż. Dominik Radziszowski

Wyjątki

W czasie wykonania programu mogą wystąpić różne rodzaje błędów:

• po wywołaniu metody obiektu może się okazać, że że obiekt ten ma problemy ze swoim stanem wewnętrznym (niezgodności wartości zmiennych instancyjnych)

• obiekt może wykryć błąd w danych na których operuje (błąd operacji plikowej , błąd sieci komputerowej)

• obiekt może wykryć naruszenie podstawowych zasad kontraktu

Wielu programistów unika pisania kodu, który sprawdzałby wszystkie możliwe warunki poprawności, ponieważ:

• kod, który przy wywołaniu każdej metody sprawdza wiele różnych warunków staje się nieczytelny (konflikt między poprawnością a czytelnością)

• po prostu nie zdają sobie sprawy z wszystkich niepoprawnych sytuacji

Wyjątki stanowią elegancką metodę sprawdzania poprawności wykonywanych opreacji bez zmniejszania czytelności kodu.

Zróbmy sobie hamburgera...

Diagram klas

D iag ram k las

Mieso Bulka

Pomidory Ogorki

Salatka

Hamburger

relacja: składa się z (agregacja)

public class BarSzybkiejObsulugi { public static void main(String[] args) {

Hamburger jedzonko = Hamburger.dajHamburgera();Hamburger drugi = Hamburger.dajHamburgera();

}}

public class Hamburger {private Mieso mieso;private Bulka bulka;private Salatka salatka;

public static Hamburger dajHamburgera() {Hamburger tmp = new Hamburger();tmp.mieso = Mieso.dajMieso();tmp.bulka = Bulka.dajBulke();tmp.salatka = Salatka.dajSalatke();if ((tmp.mieso != null) && (tmp.bulka != null)

&& (tmp.salatka != null)) {return tmp;

}else {

return null;}

}

}

public class Mieso {private static int ileNaStanie = 3;public static Mieso dajMieso() {

if (ileNaStanie > 0) {ileNaStanie--;return new Mieso();

}else {

System.out.println("nie ma miesa");return null;

}}

}

public class Bulka {private static int ileNaStanie = 1;public static Bulka dajBulke() {

if (ileNaStanie > 0) {ileNaStanie--;return new Bulka();

}else {

System.out.println("nie ma bulki");return null;

}}

}

public class Salatka {private Pomidory pomidory;private Ogorki ogorki;

public static Salatka dajSalatke() {Salatka tmp = new Salatka();tmp.pomidory = Pomidory.dajPomidory();tmp.ogorki = Ogorki.dajOgorki();if ((tmp.pomidory != null) && (tmp.pomidory != null)) {

return tmp;}else {

return null;}

}}

public class Ogorki {private static int ileNaStanie = 3;public static Ogorki dajOgorki() {

if (ileNaStanie > 0) {ileNaStanie--;return new Ogorki();

}else {

System.out.println("nie ma ogorkow");return null;

}}

}

public class Pomidory {private static int ileNaStanie = 1;public static Pomidory dajPomidory() {

if (ileNaStanie > 0) {ileNaStanie--;return new Pomidory();

}else {

System.out.println("nie ma pomidorow");return null;

}}

}

Straszne, prawda?!?

Diagram klas

D iag ram k las

Mieso Bulka

Pomidory Ogorki

Salatka

Hamburger

relacja: składa się z (agregacja)

HamburgerException

Exception

relacja: dziedziczenie

public class BarSzybkiejObsulugi {public static void main(String[] args) {

try {Hamburger jedzonko = new Hamburger();Hamburger drugi = new Hamburger();}catch(HamburgerException e) {System.out.println(e.getMessage());}

}}

public class Hamburger {private Mieso mieso;private Bulka bulka;private Salatka salatka;

Hamburger() throws HamburgerException {mieso = new Mieso();bulka = new Bulka();salatka = new Salatka();

}}

public class Salatka {private Pomidory pomidory;private Ogorki ogorki;Salatka() throws HamburgerException {

ogorki = new Ogorki();pomidory = new Pomidory();

}}public class Pomidory {

private static int ileNaStanie = 3;Pomidory() throws HamburgerException {

if (ileNaStanie > 0)ileNaStanie--;

else throw new HamburgerException("nie ma pomidorow!");

}}public class Ogorki {

private static int ileNaStanie = 3;Ogorki() throws HamburgerException {

if (ileNaStanie > 0)ileNaStanie--;

else throw new HamburgerException("nie ma ogorkow!");

}}

public class Mieso {private static int ileNaStanie = 3;

Mieso() throws HamburgerException {if (ileNaStanie > 0)

ileNaStanie--;else

throw new HamburgerException("nie ma miesa!");}

}

public class Ogorki {private static int ileNaStanie = 3;

Ogorki() throws HamburgerException {if (ileNaStanie > 0)

ileNaStanie--;else

throw new HamburgerException("nie ma ogorkow!");}

}

public class HamburgerException extends Exception {HamburgerException(String message) {

super(message);}

}

Jak to działa??

Wyjątek jest zgłaszany w razie wystąpienia nieoczekiwanego błędu. Wyjątek ten może być wychwycony przez klauzulę, która została zarejestrowana wcześniej. Jeśli wyjątek nie zostaje wychwycony, to zostaje on obsłużony przez domyślną procedurę obsługi, która zwykle wypisuje komunikat na temat miejsca, gdzie dany wyjątek został zgłoszony.

Zgłoszenie wyjątku, czyli instrukcja throw i klauzula throws

public int zamienCzasNa12h(int czas24h) throws NotProperTimeException{

if ((czas24h < 0) || (czas24h > 24))

throw new NotProperTimeException();

else if (czas24h < 12)

return czas24h;

else

return czas24h - 12;

}

Do zgłaszania wyjątków służy klauzula throw, która wymaga podania obiektu reprezentującego wyjątek.

Wyjątki kontrolowane, zgłoszone przez daną metodę, podaje się w klauzuli throws w postaci list oddzielonych przecinkami (ściśle pilnowane).

Wychwycenie wyjątku, czyli blok try i klauzule catch i finally

public static void main(String[] agrs) {

int czas = 19;

try {

int nowyCzas = zamienCzasNa12h(czas);

}

catch (NotProperTimeException e) {

System.out.println("nie podales wlasciwego czasu");

}

finally {

System.out.println("Ten fragment kodu wykonuje się zawsze!");

}

}

Kod, który może generować wyjątek umieszczamy w bloku try.

Po bloku try i klauzulach catch może występować klauzula finally. Jeśli występuje, to jest ona wykonywana zawsze po wszystkich czynnościach związanych z obsługą klauzul catch niezależnie od tego, czy wyjątek został wygenerownay i wychwycony, czy nie wychwycony, czy blok try zakończył się w wyniku przepływu sterowania, czy też w wyniku działania instrukcji break czy continue.

Po bloku try występują klauzule catch, które są przeszukiwane po wystąpieniu wyjątku w bloku try w celu rozpoznania wyjątku. Jeśli wyjątek zostanie rozpoznany zostaje on wyłapany przez catch i wykonywane są instrukje przeyporządkowane danej klauzuli catch. Jeśli wyjątek nie zostanie rozpoznany przez żadną klauzulę catch jest on propagowany na zewnątrz bloku try.

finally - posprzątaj po sobie!!

public class Switch { private boolean state = false; public boolean read() { return state; } public void on() { state = true; } public void off() { state = false; }}public class OnOffException1 extends Exception {}public class OnOffException2 extends Exception {}

public class OnOffSwitch { private static Switch sw = new Switch(); public static void f() throws OnOffException1,OnOffException2 {} public static void main(String[] args) { try { sw.on(); f(); } catch(OnOffException1 e) { System.err.println("OnOffException1"); } catch(OnOffException2 e) { System.err.println("OnOffException2"); }finally {sw.off(); } }}

Wyjątki w Javie dzielimy na:

• kontorlowane (checked exceptions) - kompilator jest w stanie sprawdzić, że każda metoda zgłasza tylko te wyjątki, które są jawnie wymienione w jej deklaracji.

• niekontrolowane (uncheckcked exceptions) - standardowe wyjątki zgłaszane przez system wykonawczy (są podklasami klas RuntimeException i Error). Każda metoda może je zgłosić i nie musi to być uwzględnione w jej kontrakcie.

Error

Runtim eException OurExceptions

Exception

Throwable

Objec t

relacja: dziedziczenie

Klasy RuntimeException - niektóre wyjątki

• ArthimeticException extends RuntimeExceptionbłąd operacji arytmetycznej (np. dzielenie przez 0)

• ClassCastException extends RuntimeExceptionpróba nieprawidłowej konwersji typu

• IllegalArgumentException extends RuntimeExceptionprzekazanie do metody niewłaściwego argumentu

• IndexOutOfBoundsException extends RuntimeExceptionpróba odwołanie się do tablicy (luba napisu) poza poprawnymi granicami indexu

• NegativeArraySizeException extends RuntimeExceptionpróba utworzenia tablicy o ujemnym rozmiarze

• NullPointerException extends RuntimeExceptionużycie null do wywołania metody lub uzyskania dostpu do pola obiektu; otrzymanie argumentu null przez metodę, która nie akceptuje referencji null.

RuntimeException - wyjątki, o które powinien zadbać programista, wynikają najczęściej z jego przeoczeń.

Klasy Error - niektóre wyjątki

• OutOfMemoryError extends VitrualMachineError brak pamięci

• StackOverfowError extends VirtualMachineErrorprzpełnienie stosu (np. z powodu nieskończonej rekurencji)

• NoSuchFieldError extends IncomaptibileClassChangeErrorw klasie lub interfejsie nie znaleziono określonego pola

• NoSuchMethodError extends IncomaptibileClassChangeError w klasie lub interfejsie nie znaleziono określonej metody

• AbstractMethodError extends IncomaptibileClassChangeError wywołanie metody abstrakcyjnej (tylko w szczególnych okolicznościach)

• ClassFormatError extends LinkageErrorładowana klasa lub interfejs ma niewłaściwy format (np. uszkodzenie pliku)

Error - wyjątki, które sygnalizują poważne, w większości nienaprawialne błędy. Nie powinny być one przechwytywane i obsługiwane.

Konstruktory Wyjątków

Standardowo wyjątki zawierają cztery konstruktory (są to tak naprawdę konstruktory klasy Throwable, po której dziedziczą wszystkie wyjątki):

• Throwable() - bezparametrowy , ustawaiający detail message (opis wyjątku) na null

• Throwable(String message) - przyjmuje napis message jako detail message wyjątku (można go uzyskać od wyjątku za pomocą metody getMessage().

• Throwable(Throwable cause) - konstruuje nowy wyjątek na podstawie starego, przejmując od niego detail message i call stack trace (miejsce wywołania na stosie); wykorzystujemy ten konstruktor, gdy przechwytujemy jeden wyjątek aby rzucić następny (exception chaining), lecz inny (ze względu na np. zmianę warstwy abstrakcji)

• Throwable(String message, Throwable cause) - jak wyżej, tyle że podmienia detail message na message.

Co może nieść ze sobą wyjątek?

class NotProperTimeException extends Exception {

private int zlyCzas;

NotProperTimeException() {}

NotProperTimeException(String s) {

super(s);

}

NotProperTimeException(String s, int czas) {

super(s);

zlyCzas = czas;

}

public int getZlyCzas() { return zlyCzas; }

}

Wyjątki mogą również dostarczać więcej informacji o występujących błędach. Wszystko zależy od tego jak my je zaprojektujemy.

public int zamienCzasNa12h(int czas24h) throws NotProperTimeException{

if ((czas24h < 0) && (czas24h > 24))

throw new NotProperTimeException("zla liczba", czas24h);

else if (czas24h < 12)

return czas24h;

else

return czas24h - 12;

}

public static void main(String[] agrs) {

int czas = 19;

try {

int nowyCzas = zamienCzasNa12h(czas);

}

catch (NotProperTimeException e) {

System.out.println(e.getMessage() + " zły agrument: " + e.getZlyCzas());

}

}

Użyteczne metody klasy Throwable

• String getMessage() - zwraca napis podany kontruktorowi wyjątku Exception

• String toString() - zwraca napis reprezentujący nazwę wyjątku (klasy wyjątku)

• void printStackTrace() - wypisuje call stack trace czyli sekwencję metod, która została wywołana do momentu wyrzucenia wyjątku

OOP a Wyjątki

I temvo id n ic () th row s M yE xcep tion

A b s trac tItemab s trac t vo id n ic () th row s M yE xcep tion

Kiedy korzystamy z virtualności metody (overriding a method) możemy wyrzucać wyjątek takiego typu (lub jego podtypu), który został zadeklarowany przez klauzule throws w klasie bazowej tej metody.

Co można zrobić z wyjątkiem??

• wychwycić i obsłużyć• wychwycić i przekształcić na inny wyjątek zadeklarowany w

klauzuli naszej metody (exception chaining)• wymienić ten wyjątek w klauzuli throws naszej metody i

pozwolić na jego propagację do miejsca wywołania naszej metody, nie zajmując się jego obsługą (chyba że w klauzuli finally)

Konwencje, czyli nawyki dobrego programowania

• throw new Exception();zawsze tworzyć instancje obiektów w momencie ich zgłaszania - ułatwia to odnalezienie miejsca na stosie, w którym zgłoszono wyjątek

• class MyException extends Exception {}własne tworzymy rozszerzając klasę Exception, a nie Throwable, tworząc z nich wyjątki kontrolowane - musimy je dekalrować przy definicjach funkcji i nie pojawiają się nie wiadomo skąd.

• catch(Error e) {} NIEnie przechwytujmy wyjątków klasy Error, ponieważ oznaczają one najczęściej nienaprawialny błąd.

• catch(Exception e) {} NIEnie przechwytujmy wszystkich możliwych wyjątków klasy Exception, starajmy się przechwytywać wyjątki jak najkonkretniejszych typów.

Używać wyjątków czy nie, oto jest pytanie???

• Handle problems at the appropriate level. (Avoid catching exceptions unless you know what to do with them).

• Fix the problem and call the method that caused the exception again.

• Patch things up and continue without retrying the method.

• Calculate some alternative result instead of what the method was supposed to produce.

• Do whatever you can in the current context and rethrow the same exception to a higher context.

• Do whatever you can in the current context and throw a different exception to a higher context.

• Terminate the program.

• Simplify. (If your exception scheme makes things more complicated, then it is painful and annoying to use.)

• Make your library and program safer. (This is a short-term investment for debugging, and a long-term investment for application robustness.)

Use exceptions to:

Nie używać wyjątków do oczekaiwanych i zwykłych sytuacji, np. czytając strumień danych, wiadomo że ten strumień się kiedyś skończy (jest to normalne)

while (!stream.eof())

process(stream.next());

stream.close();

try {

while (true) {

process(stream.nrext());

}

}

catch(StreamEndException e) {

stream.cleose();

}

Rzutowaniei

Operatorinstanceof

Dwa słowa o konwersjach

jawn e(rzu towan ie )

n ie jawn e

K on w ers je

Konwersje występują:

• przy operatorach przypisania

• w wyrażeniach

• przy przekazywaniu parametrów

Konwersje niejawne typów pierwotnych

• występują automatycznie• każdą zmienną liczbową można przypisać zmiennej która

obejmuje szerszy zakres wartości. • char ==> int• float ==> double• int ==> float• mogą powodować utratę dokładności (nie zakresu)

duży long ==> float =(rzutowanie)=> long

Konwersje jawne typów pierwotnych (rzutowanie)

• występują za pomocą operatora rzutowaniaint x;long y = 100L;x = (int) y;

• mogą powodować utratę zakresu (double ==> float, nieskończoność) i dokładności

• zmiennopozycyjna ==> całkowitoliczbowa (zaokrąglenie w stronę 0)

• całkowitoliczbowa ==> całkowitoliczbowa (obcięcie najstarszych bitów)

B ia laC zeko lad a C zarn aC zeko lad a

C zeko lad a

Diagram klas

relacja: dziedziczenie

Konwersje niejawne referencji

• obiekt będący instacją jakiejś klasy jest też instancją każdego z jej nadtypów. Referencję do niego można zatem użyć w każdym kontekście wymagającym referencji do któregokolwiek z nadtypów.

• W naszym przykładzie możemy użyć referencji typu Czekolada do obiektu typu CzarnaCzekoladaCzekolada pychotka = new CzarnaCzekolada();

• dygresja: referencję null możemy przypisać każdej zmiennej referencyjnej.

• Tą konwersję nazywamy konwersją w górę (upcasting) lub bezpieczną konwersją.

Konwersje jawne referencji (rzutowanie)

• a teraz chcemy z powrotem:CzarnaCzekolada moja = (CzarnaCzekolada) pychotka;

• tą konwersję nazywamy konwersją w dół (downcasting) lub niebezpieczną konwersją.

• A jak się pomylimy i pychotka tak naprawdę nie jest typu CzarnaCzekolada to zostanie zgłoszony wyjątek ClassCastException

A co jak nie wiemy którego z podtypów danej klasy jest dany obiekt, a koniecznie musimy go zrzutować?

Przecież znamy wyjątki!Możnaby próbować rzutować na każdy typ po kolei i przechwytywać wyjątek ClassCastException i próbować z następnym typem aż do udanej konwersji.

Ale czy to takie eleganckie??

NIE!! Nie dość że nieeleganckie to jeszcze jest przejawem złego stylu programowania!!

TO NIE JEST DOBRE MIEJSCE NA UŻYCIE WYJĄTKÓW

Operator instanceof

public void zjedz(Czekolada pychotka) {

if (pychotka instanceof CzarnaCzekolada) {

CzarnaCzekolada moja = (CzarnaCzekolada) pychotka;// wykorzystanie funkcjonalności klasy CzarnaCzekolada

}

else {

BialaCzekolada moja = (BialaCzekolada) pychotka;

//wykorzystanie funkcjonalności klasy BialaCzekolada

}

}

Uwaga: w powyższym przykładzie operator instanceof zwróci również true, gdy obiekt będzie tak naprawdę obiektem klasy CzarnaCzekoladaZOrzeszkami, będącą podklasą klasy CzarnaCzekolada.

C ia loR own ia C ia loP och yln ia R ow n ia

A b s trac tB od y

V ec to r

P lan sza

relacja: składa się z (agregacja) relacja: dziedziczenie

public abstract class AbstractBody {public abstract void paint(Graphics display);

}

public class CialoGora extends AbstractBody {public void paint(Graphics display) {

//tu się rysuje ciało na równi}

}

public class CialoPochylnia extends AbstractBody {public void paint(Graphics display) {

//tu się rysuje ciało na pochylni}

}

public class Rownia extends AbstractBody {public void paint(Graphics display) {

// tu się rystuje równia}

}

public class Plansza extends Panel{

private Vector items;

Plansza() {items = new Vector();items.addElement( new Rownia());items.addElement( new CialoGora());items.addElement( new CialoPochylnia());

}

public void paint(Graphics display) {for (int i = 0; i < items.size(); i++) {

((AbstractBody)(items.elementAt(i))).paint(display);}

}}

Wykorzystane materiały

• "Java TM" Ken Arnold i James Gosling

• "Thinking in Java" 3 wydanie, Bruce Eckel

• Kursy Javy firmy Sun

• Java API Documentation http://java.sun.com/j2se/1.4.1/docs/api/index.html

• "Wzorce Projektowe" Referat, Piotr Pycia

• "Klasy Kolekcji" Referat, Tomasz Wilczyński

• własna wyobraźnia