4. Podejmowanie decyzji: instrukcje if oraz if-else
Znana nam już instrukcja if ma postać: if (war) ins gdzie:
Instrukcja if-else rozszerza działanie instrukcji if. Ma ona postać. if (war) ins1 elseins2 gdzie:
Różnica pomiędzy zastosowaniem instrukcji if oraz if-else można zobaczyć wyraźnie na char op; double a, b, r; ... if (op == '+') r = a + b; else if (op == '-') r = a - b; else if (op == '*') r = a*b; else if (op == '/') r = a/b; else System.out.println("Błędny kod operacji");
Przy takich okazjach powstaje kwestia: które else odpowiada któremu if ?
Zasada jest prosta: danemu else odpowiada pierwsze poprzedzające go i znajdujące
się w tym samym bloku if nie mające jeszcze swojej "pary" w postaci else.
Wcięcia - poprawiające czytelność - programu w żaden sposób nie decydują
o odpowiedniości if i else. Częste błędy przy stosowaniu instrukcji if oraz if -else, na które trzeba zwracać szczególną uwagę.
A. Złe dopasowanie if i else w przypadku kilku instrukcji if (omówione przed chwilą) B. Stawianie średnika po nawiasie zamykającym warunek instrukcji if np. : if (a > b); System.out.println("a > b"); // niezależnie od tego czy a>b ! C. Zapomnienie nawiasu zamykającego instrukcję grupującą np. if (a > b) { c = a + b; d = e + f; else c = d + f; Szczególnie częstym błędem przy sprawdzaniu wielu warunków (które mogą
się na siebie "nakładać") jest stosowanie instrukcji if bez else, nie uwzględnienie
wszystkich możliwości lub nieprawidłowa kolejność sprawdzania warunków.
Błędy te są szczególnie niebezpieczne, gdyż dotyczą logiki programu i nie mogą być wykryte przez kompilator
Np. jeśli ktoś chce powiedzieć coś o liczbie a (czy jest duża, średnia, mała) to mógłby zapisać to w ten sposób: if (a >= 1000) System.out.println("Duża liczba") if (a >= 100) System.out.println("Średnia liczba") if (a >= 10) System.out.println("Mała liczba") Duża liczba
Średnia liczba Mała liczba co jest oczywistym błędem, bo jeśli a = 1000, ten fragment wyprowadzi na konsolę wzajemnie wykluczającą się informację.
Ach, potrzebne jest else, ale uwaga - kolejność sprawdzania warunków jest istotna. if (a >= 10) System.out.println("Mała liczba"); else if (a >= 100) System.out.println("Średnia liczba"); else if (a >= 1000) System.out.println("Duża liczba");
co znowu daje całkiem niepoprawny wynik dla a = 1000: napis "Mała liczba" if (a >= 1000) System.out.println("Duża liczba"); else if (a >= 100) System.out.println("Średnia liczba"); else if (a >= 10) System.out.println("Mała liczba");
Zauważmy jednak, że temu fragmentowi brakuje "zupełności": co się stanie
jeśli a równa się np. 1? Nie dostaniemy żadnej informacji! Potrzebne jest
zatem jeszcze jedno ("zamykające") else, które będzie obsługiwać wszystkie
nie uwzględnione warunki. if (a >= 1000) System.out.println("Duża liczba"); else if (a >= 100) System.out.println("Średnia liczba"); else if (a >= 10) System.out.println("Mała liczba"); else System.out.println("Liczba mikra, bo mniejsza od 10")
Czasem nie stosowanie else przy wykluczających się warunkach nie prowadzi
do błędów w programie, ale - na pewno nalezy do złego stylu i powoduje niepotrzebne
sprawdzanie warunków, o których już wiadomo, że są fałszywe.
Z punktu widzenia użytkownika bankomatu ważne jest tylko to, że bankomat
pyta o PIN a następnie o kwotę do wypłaty i (ewentualnie) ją wypłaca. class BankomatTest { public static void main(String[] args) { Bankomat b = new Bankomat(); b.askPin(); b.askAmmountAndWithdraw(); System.exit(0); } }
A jego działanie pokazuje następująca sekwencja dialogów (generowanych przez klasę Bankomat):
Gdyby numer PIN okazał się nieprawidłowy - to klasa Bankomat powinna o tym
poinformować w wywołaniu metody askPin (i oczywiście nie dopuścić do pytania
o kwotę), a gdyby żądana kwota przekraczała limit - również poinformować
i nie dopuścić do wypłaty:
Uwaga. Nie możemy teraz sprawdzać, czy podana kwota do wypłaty jest liczbą
całkowitą, bo jeszcze nie omówiliśmy zgadnień związanych z wyjątkami. Uzupełnimy
to później
Istotną rolę będzie w niej odgrywać sprawdzanie poprawności wprowadzanych danych, które zapiszemy właśnie za pomocą instrukcji if-else.
Zobaczmy teraz jak wygląda klasa Bankomat.
Oczywiście, bankomat - sprawdzając dane - komunikuje się z jakimś "kartowym"
czy bankowym, centrum. W naszym programie będzie go (w uproszczony sposób)
reprezentować klasa CardIdent (na razie potraktujmy ją jako daną, bo jej
konstrukcja wykracza poza omówiony dotąd materiał). Przypomnijmy, że uzyskana w dialogu kwota do wypłaty jest napisem. Musimy
go przekształcić na liczbę za pomocą metody Integer.parseInt()
Metoda askAmmountAndWithdraw pyta o kwotę do wyplaty - będzie ją przechowywac w zmiennej ammount (ale tylko w przypadku, gdy jest już ustalony pin; jeśli pin był wadliwy, to pole currentPin zawiera null i metoda konczy działanie z wynikem false - nie będzie wyplaty; to zapewniamy w pierwszym wierszu metody, pisząc if (currentPin == null) return false;).
Jeśli kwota do wypłaty przekracza limit - to do wypłaty też nie dochodzi
i pojawia się odpowiedni komunikat. W przeciwnym razie - kwota jest wypłacana,
do centrum kartowego posyłany jest komunikat o wypłaconej kwocie po to, by
ew. zmniejszyć dzienny limit ( CardIdent.changeLimit(currentPin, ammount);
), a wartości pól currentPin i currentLimit są zerowane w przygotowaniu do
następnej transakcji. import javax.swing.*; public class Bankomat { private static String CANCEL_MSG = "Zrezygnowano z transakcji. Do widzenia"; private String currentPin; private int currentLimit; public Bankomat() { CardIdent.init(); } public boolean askPin() { String pin = ask("Wprowadz numer PIN:"); boolean pinOk = false; int limit = 0; if (pin == null) say(CANCEL_MSG); else { limit = CardIdent.getLimit(pin); if (limit == -1) say("Wadliwy PIN"); else { pinOk = true; currentPin = pin; currentLimit = limit; } } return pinOk; } public boolean askAmmountAndWithdraw() { if (currentPin == null) return false; boolean withdrawAccepted = false; String request = ask("Podaj kwote do wyplaty:"); if (request == null) say(CANCEL_MSG); else { int ammount = Integer.parseInt(request); if (ammount > currentLimit) say("Limit przekroczony."); else { CardIdent.changeLimit(currentPin, ammount); say("Wyplacam kwote : " + ammount + " zl"); withdrawAccepted = true; } } currentPin = null; return withdrawAccepted; } private String ask(String txt) { return JOptionPane.showInputDialog(txt); } private void say(String txt) { JOptionPane.showMessageDialog(null, txt); } Zwróćmy też uwagę na dwa elementy:
W katalogu samples\bankomat9 znajdują się wszystkie omawiane klasy.
|