Sierpień 1, 2018

Instrukcje warunkowe i sterujące

Instrukcje warunkowe i sterujące

Jeżeli opanowałeś już w 100% operatory logiczne i tworzenie warunków logicznych przy ich użyciu to czas na trochę ciekawsze zagadnienie – na instrukcje warunkowe i sterujące.

Jak same nazwy wskazują coś będzie zależało od warunku i coś będziemy mogli przełączać w zależności od potrzeby – mają bowiem one ścisły związek z warunkami logicznymi. To właśnie na podstawie ich rezultatu (true/false) mogą być wykonane konkretne akcje w aplikacji. Przejdźmy do sedna.

Instrukcje warunkowe

Rozpocznijmy od częściej stosowanej metody kierowania aplikacją – tzn. instrukcji warunkowej IF i jej kolejnych składowych.

Na początek zdefiniujmy sobie szablon kodu, do którego będziemy pisać nasze wypociny, Nic skomplikowanego – Scanner do odczytywania wartości z klawiatury i tyle.

package pl.maniaq;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
    }
}

if

Jak można się domyśleć z języka angielskiego if oznacza jeżeli. Można się domyślać, że jeżeli coś jest prawdą to wykonaj konkretną akcję.

Dokładnie tak jest – if, służy do wykonywania konkretnych akcji, jeżeli dany warunek zostaje spełniony – czyli rezultatem jest true.

Przykład, może być prosty i nawiązujący do lekcji z operatorami matematycznymi – jeżeli dzielnik jest równy 0 to nie wykonuj dzielenia. Pozwala nam to na stworzenie prostego zabezpieczenia podczas tworzenia m.in. kalkulatora.

Czas przejść do przykładu, przypuśćmy, że chcemy sprawdzić czy podana liczba przez użytkownika jest parzysta – jeżeli tak to wypisać na ekran odpowiedni komunikat. Pisząc kod wykorzystamy powyższy szablon klasy Main.

Zacznijmy od początku, najpierw musimy odczytać liczbę od użytkownika co nie powinno stanowić już dla Ciebie problemu.

System.out.println("Podaj liczbę: ");
int number = scanner.nextInt();

Teraz musimy się zastanowić jak wyznaczyć liczbę parzystą – podpowiem, że można skorzystać z operatora modulo %.

Reszta z dzielenia liczby parzystej przez 2 jest zawsze równa 0 – a operator modulo zwraca właśnie resztę z dzielenia dwóch liczb. Zapiszmy, więc ten warunek do zmiennej typu boolean.

boolean isEvenNumber = number % 2 == 0;

Zapisaliśmy właśnie, że jeżeli reszta z dzielenia jest równa 0 to otrzymamy prawdę – czyli liczba jest parzysta.

Czas na użycie instrukcji if do wypisania komunikatu użytkownikowi – nic skomplikowanego – schemat wygląda tak:

if (warunek) {
  //zrób coś, gdy warunek spełniony
}

Zastosujmy to w naszym kodzie.

if(isEvenNumber){
    System.out.println("Liczba "+number+" jest parzysta!");

Oczywiście, możemy zapisać też to w ten sposób:

if(number % 2 == 0){
    System.out.println("Liczba "+number+" jest parzysta!");
}

Jednak pierwsza wersja jest dużo czytelniejsza – szczególnie w trudniejszych warunkach logicznych! Dlatego proponuję Ci stosowanie pierwszego wariantu.

Jako ciekawostkę warto też wspomnieć, że można pominąć klamry, gdy mamy do wykonania tylko jedną instrukcję w bloku if. Wyglądałoby to tak:

if(isEvenNumber)
    System.out.println("Liczba "+number+" jest parzysta!");

Choć lepiej utworzyć od razu klamry, ponieważ może w przyszłości kod będzie rozwijany i będziemy wtedy zmuszeni do utworzenia tych klamr – co może wtedy być irytujące.

Jednak uruchommy nasz program – nieważne w jakiej formie.

Podaj liczbę: 
10
Liczba 10 jest parzysta!

Program działa poprawnie, jednak co w przypadku, gdy podamy liczbę nieparzystą?

Podaj liczbę: 
7

W takim przypadku nie otrzymujemy żadnej informacji – jak temu zaradzić?

else

Z pomocą przychodzi do nas instrukcja else – tzn. w przeciwnym wypadku. 

Zasada jej działania jest prosta – jeżeli if nie jest spełniony to w takim wypadku zostanie wykonany blok else. Dodajmy, więc do naszego bloku if blok else informujący użytkownika o efekcie.

if(isEvenNumber){
    System.out.println("Liczba "+number+" jest parzysta!");
}else{
    System.out.println("Liczba "+number+" jest nieparzysta!");
}

Z bloku else również można usunąć klamry jeżeli mamy tylko jedną instrukcję.

Po uruchomieniu programu otrzymujemy taki efekt:

Podaj liczbę: 
7
Liczba 7 jest nieparzysta!

Czyli mamy obsłużone oba przypadki – dzięki czemu użytkownik jest o wszystkim poinformowany.

else if

Do naszego bloku if możemy nie tylko dodać blok else, ale możemy dodać nieskończoną ilość bloków else if – które definiują kolejne warunki.

Trzeba pamiętać, że zawsze if jest pierwszy blokiem, a else ostatnim – między nimi możemy wstawiać ile tylko chcemy bloków else if – jednak najlepiej jak najmniej, z puntku czytelności kodu.

Rozpocznijmy ponownie od szablonu klasy Main, tym razem poinformujmy użytkownika czy liczba jest dodatnia, ujemna, czy może równa zero. Jak widać już na początek mamy trzy warunki – pierwszym z nich może być to, że liczba jest dodatnia, drugim że liczba jest ujemna – a ostatnim, że liczba jest równa 0 – ostatni warunek bez problemu możemy zamknąć w blok else, ponieważ nie ma innych warunków do spełnienia.

Zacznijmy od takiego stanu:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("Podaj liczbę: ");
        int number = scanner.nextInt();
     
    }
}

Pierwszy warunek – liczba jest dodatnia:

boolean isPositive = number > 0;

if(isPositive){
    System.out.println("Liczba jest dodatnia.");
}

Drugi warunek – liczba jest ujemna:

boolean isPositive = number > 0;
boolean isNegative = number < 0;

if(isPositive){
    System.out.println("Liczba jest dodatnia.");
}else if(isNegative){
    System.out.println("Liczba jest ujemna.");
}

Zauważ, że bez problemu możesz skompilować kod nie mając nawet bloku else – bloki else if i else są opcjonalne!

Na koniec trzeci warunek – możemy go zapisać jako kolejny else if, jednak my to zrobimy w bloku else.

boolean isPositive = number > 0;
boolean isNegative = number < 0;

if(isPositive) {
    System.out.println("Liczba jest dodatnia.");
}else if(isNegative) {
    System.out.println("Liczba jest ujemna.");
}else {
    System.out.println("Liczba jest równa 0.");
}

Możemy teraz sprawdzić działanie programu.

Podaj liczbę: 
-3
Liczba jest ujemna.

Kolejne warunki sprawdź samemu – spróbuj również zapisać trzeci warunek w bloku else if zamiast w else.

To na tyle instrukcji warunkowej if – nadchodzi czas na omówienie instrukcji sterującej!

Instrukcja sterująca

Instrukcja sterująca działa tak samo jak instrukcja warunkowa – wykonuje ona określoną akcję po spełnieniu warunku – różni się tak naprawdę ona konstrukcją.

Zacznijmy jej budowanie, wszystko dzieje się w bloku switch, który ma taką konstrukcję:

switch (zmienna-sterująca) {

}

Stwórzmy sobię zmienną sterującą i blok

int radix = 1;

switch(radix) {
}

Oczywiście zmienna sterująca może być odczytana od użytkownika – tak też zróbmy.

int radix = scanner.nextInt();

switch(radix) {
}

Instrukcja switch bardzo dobrze się sprawdza, gdy chcemy stworzyć np. proste menu dla użytkownika w konsoli – wtedy, zależnie od klikniętego przycisku możemy wykonać konkretną akcję – stwórzmy na początku proste menu przy użyciu System.out.println.

System.out.println("1 - Pomnóż dwie liczby");
System.out.println("2 - Dodaj dwie liczby");
System.out.println("3 - Oblicz resztę z dzielenia");
System.out.println("0 - Zakończ działanie programu");
System.out.println("Co chcesz zrobić? ");
int radix = scanner.nextInt();

switch(radix) {
}

Dając taką informację użytkownikowi możemy odpowiednio zareagować na wciśnięcie przycisku – do tego posłuży nam case.

Case jest tak naprawdę warunkiem – jeżeli jest spełniony to oczywiście wykonujemy jego blok.

switch(radix) {
    case 1:
        System.out.println("Mnozenie dwóch liczb");
    case 2:
        System.out.println("Dodawanie dwóch liczb");
    case 3:
        System.out.println("Obliczanie reszty z dzielenia");
    case 0:
        System.out.println("Zakończenie działania programu.");
}

:Case 1 zostanie spełniony, gdy zmienna sterująca radix jest równa 1 – i tak dla każdego case. Przetestujmy nasz program.

1 - Pomnóż dwie liczby
2 - Dodaj dwie liczby
3 - Oblicz resztę z dzielenia
0 - Zakończ działanie programu
Co chcesz zrobić? 
0
Zakończenie działania programu.

Na zero zareagował poprawnie – spróbujmy innych opcji.

1 - Pomnóż dwie liczby
2 - Dodaj dwie liczby
3 - Oblicz resztę z dzielenia
0 - Zakończ działanie programu
Co chcesz zrobić? 
2
Dodawanie dwóch liczb
Obliczanie reszty z dzielenia
Zakończenie działania programu.

No i w tym wypadku coś poszło nie tak – co poszło nie tak?

W naszych case brakuje jeszcze słowa kluczowego break, który wychodzi z całego bloku switch – zamiast wykonywać resztę dostępnych case’ów.

Nasz kod wygląda teraz tak:

System.out.println("1 - Pomnóż dwie liczby");
System.out.println("2 - Dodaj dwie liczby");
System.out.println("3 - Oblicz resztę z dzielenia");
System.out.println("0 - Zakończ działanie programu");
System.out.println("Co chcesz zrobić? ");
int radix = scanner.nextInt();

switch(radix) {
    case 1:
        System.out.println("Mnozenie dwóch liczb");
        break;
    case 2:
        System.out.println("Dodawanie dwóch liczb");
        break;
    case 3:
        System.out.println("Obliczanie reszty z dzielenia");
        break;
    case 0:
        System.out.println("Zakończenie działania programu.");
        break;
}

Po uruchomieniu:

1 - Pomnóż dwie liczby
2 - Dodaj dwie liczby
3 - Oblicz resztę z dzielenia
0 - Zakończ działanie programu
Co chcesz zrobić? 
2
Dodawanie dwóch liczb

Teraz działa wszystko dobrze – instrukcja break nie pozwala na wykonanie kolejnych case’ów.

Wszystko jest w porzadku, ale co w sytuacji gdy użytkownik poda inną wartość?

1 - Pomnóż dwie liczby
2 - Dodaj dwie liczby
3 - Oblicz resztę z dzielenia
0 - Zakończ działanie programu
Co chcesz zrobić? 
5

Nie mamy obsłużonych wszystkich możliwych sytuacji – jednak może istnieje coś takiego jak else?

Dokładnie tak, odpowiednikiem else jest default – który wykonuje się, gdy żaden case nie jest spełniony!

Dodajmy teraz default do naszego programu:

System.out.println("1 - Pomnóż dwie liczby");
System.out.println("2 - Dodaj dwie liczby");
System.out.println("3 - Oblicz resztę z dzielenia");
System.out.println("0 - Zakończ działanie programu");
System.out.println("Co chcesz zrobić? ");
int radix = scanner.nextInt();

switch(radix) {
    case 1:
        System.out.println("Mnozenie dwóch liczb");
        break;
    case 2:
        System.out.println("Dodawanie dwóch liczb");
        break;
    case 3:
        System.out.println("Obliczanie reszty z dzielenia");
        break;
    case 0:
        System.out.println("Zakończenie działania programu.");
        break;
    default:
        System.out.println("Wybrana opcja nie jest obsługiwana.");
        break;
}

I dzięki temu obsługujemy każde zachowanie użytkownika:

1 - Pomnóż dwie liczby
2 - Dodaj dwie liczby
3 - Oblicz resztę z dzielenia
0 - Zakończ działanie programu
Co chcesz zrobić? 
5
Wybrana opcja nie jest obsługiwana.

Podsumowanie

To już wszystko na temat instrukcji warunkowych i sterujących – pozostało tak naprawdę tylko utrwalić sobie wiedzę samodzielnymi zadaniami.

  1. Na podstawie liczby podanej przez użytkownika wypisz na ekran czy liczba jest parzysta, czy też nie.
  2. Wypisz na ekran czy liczba jest dodatnia, czy ujemna.
  3. Na podstawie liczby podanej od użytkownika sprawdź w jakim przedziale mieści się liczba: od 0 do 10, od 11 do 20, od 21 do 30, od 31 do 40 czy może 41 do 50. Wypisz na ekran informację o przedziale, jeżeli liczba nie mieści się w żadnym z nich to wyświetl informację: „Liczba nie należy do żadnego z przedziałów”.
  4. Przy użyciu instrukcji sterującej switch stwórz prosty kalkulator z funkcjami: dodawania, odejmowania, mnożenia, dzielenia i liczenia reszty z dzielenia. Dodaj do tego też menu, aby użytkownik wiedział jaką opcję może wybrać.
  5. Stwórz obiekt Random: Random generator = new Random() – i przy użyciu generator.nextInt(maksymalna_liczba) do wygenerowania liczby z przedziału od 0 do wskazanej jako parametr i sprawdź użytkownik odgadł liczbę.

Jak przy każdym zadaniu przypominam o stosowaniu angielskich nazw zmiennych!

Rozwiązania zadań możesz znaleźć tutaj.

Skoro to już wszystko na temat warunków i sterowania to możemy przejść do kolejnego zagadnienia – tablice!