Spis treści
- Rozdział 4 - Instrukcje warunkowe
- Podstawy instrukcji warunkowych
- Operatory relacyjne
- Typ boolean
- Warunki instrukcji if
- Operatory warunkowe i operator logiczny !
- Tablica prawdy operatorów warunkowych
- Nawiasy i priorytety operatorów warunkowych
- Short-circuit evaluation
- Zagnieżdżanie instrukcji warunkowych
- Bloki kodu i zakresy zmiennych
- Instrukcja switch
- Trój-argumentowy operator logiczny
- Podsumowanie
- Pytania
- Zadania
Ważnym konceptem w programowaniu jest zakres widoczności i "życia" zmiennych i innych obiektów.
Spójrzmy na poniższy przykład – jaki będzie wynik działania tego programu?
public class UzyciePrzedDefinicja {
public static void main(String[] args) {
System.out.println("Liczba = " + liczba);
int liczba = 5;
}
}
Powyższy program w ogóle się nie skompiluje – kompilator zgłosi błąd, ponieważ próbowaliśmy użyć zmiennej liczba zanim ją zdefiniowaliśmy w metodzie main:
Zmienna liczba istnieje dopiero od linii, w której zostanie zdefiniowana.
Spójrzmy na kolejny przykład – jaki będzie wynik Twoim zdaniem?
public class ZmiennaWBlokuIf {
public static void main(String[] args) {
int licznik = 9;
int mianownik = 3;
if (mianownik != 0) {
double wynik = licznik / mianownik;
}
System.out.println("Wynik = " + wynik);
}
}
Program ponownie się nie skompiluje:
Kompilator protestuje, ponieważ nie wie czym jest "wynik".
Powodem jest fakt, że zmienną wynik utworzyliśmy w bloku instrukcji if. Zakres "życia" zmiennej wynik to jedynie blok instrukcji if – poza nim, zmienna ta przestaje istnieć i jest niedostępna w dalszej części kodu.
Spójrzmy na jeszcze jeden przykład:
Kolorami zaznaczone są fragmenty kodu, w których dostępne są poszczególne zmienne:
- Zmienna trzeciaLiczba dostępna jest jedynie w zagnieżdżonym bloku instrukcji if, ponieważ została w nim zdefiniowana – poza tym blokiem, zmienna trzeciaLiczba nie istnieje.
- Z kolei zmienna drugaLiczba dostępna jest zarówno w "głównym" bloku if, jak i w drugim, zagnieżdżonym w nim, bloku if. Zagnieżdżone bloki kodu mają dostęp do zmiennych zdefiniowanych wcześniej w zewnętrznych blokach, ale nie na odwrót.
- Zmienna liczba dostępna jest w całej metodzie main, od jej początku, aż do końca metody, ponieważ została zdefiniowana na samym jej początku.
W sekcji else głównej instrukcji warunkowej mamy dostęp jedynie do zmiennej liczba, ponieważ została zdefiniowana wcześniej w zewnętrznym bloku (którym jest ciało metody main). W sekcji else ani zmienna drugaLiczba, ani trzeciaLiczba, nie są znane, bo jeżeli doszło do wykonania kodu w sekcji else, to zmienne te nie zostały nigdy utworzone.
Bloki kodu w instrukcjach warunkowych¶
Na początku rozdziału o instrukcjach warunkowych dowiedzieliśmy się, że klamry przed i po instrukcjach przyporządkowanych do danej sekcji instrukcji warunkowej nie są wymagane, jeżeli do wykonania jest tylko jedna instrukcja – poniższy kod:
int x = 5;
if (x > 0) {
System.out.println("x jest wieksze od 0.");
} else if (x < 0) {
System.out.println("x jest mniejsze od 0.");
} else {
System.out.println("x jest rowne 0.");
}
moglibyśmy zapisać także jako:
int x = 5;
if (x > 0)
System.out.println("x jest wieksze od 0.");
else if (x < 0)
System.out.println("x jest mniejsze od 0.");
else
System.out.println("x jest rowne 0.");
Wynika to z faktu, że w powyższym przykładzie sekcje warunkowe mają po jednej instrukcji do wykonania. Powinniśmy jednak zawsze stosować klamry { }, nawet wtedy, gdy instrukcja warunkowa ma przypisaną tylko jedną instrukcję do wykonania.
Zobaczmy w poniższym przykładzie-zagadce co może się stać, jeżeli zapomnimy otoczyć więcej niż jedną instrukcję w klamry:
import java.util.Scanner;
public class IfBezBloku {
public static void main(String[] args) {
int licznik, mianownik;
System.out.println("Podaj licznik:");
licznik = getInt();
System.out.println("Podaj mianownik:");
mianownik = getInt();
double wynik;
if (mianownik != 0)
wynik = licznik / mianownik;
System.out.println("Wynik: " + wynik);
}
public static int getInt() {
return new Scanner(System.in).nextInt();
}
}
Jaki będzie wynik działania powyższego programu?
Program nawet się nie skompiluje! Zobaczymy komunikat, który widzieliśmy już w jednym z przykładów w poprzednim rozdziale, gdy poznawaliśmy zmienne:
Dlaczego zobaczyliśmy powyższy błąd? Nie otoczyliśmy obu linijek pod instrukcją if klamrami, więc do instrukcji if przyporządkowana jest tylko jedna instrukcja – nadanie wartości zmiennej wynik.
Jak wiemy z poprzedniego rozdziału, każdej zmiennej, zanim zostanie użyta, musi zostać nadana jakaś wartość.
W powyższym kodzie nadajemy zmiennej wynik wartość tylko w przypadku, gdy zmienna mianownik ma wartość różną od zera, więc istnieje taka ścieżka wykonania programu, w której zmiennej wynik nie zostałaby przypisana żadna wartość przed jej wypisaniem w linijce:
System.out.println("Wynik: " + wynik);
Kompilator Java jest na tyle "mądry", że jest w stanie wychwycić takie sytuacje i poinformować nas o nich jeszcze na etapie kompilacji.
Gdybyśmy nie zapomnieli o objęciu obu instrukcji (nadania wartości i jej wypisania) w blok za pomocą nawiasów klamrowych { }, to próba wypisania wartości odbyła by się tylko po uprzednim nadaniu jej wartości, dzięki czemu kod byłby poprawny, a kompilator by nie protestował.
Cześć,
Można prosić o komentarz z tym jak powinien wyglądać powyższy zapis (IfBezBloku.java)?
Cześć, masz na myśli jak ten program powinien wyglądać, żeby kompilował się bez błędu? Trzeba opakować obie instrukcje pod instrukcją warunkową
ifw nawiasy klamrowe:import java.util.Scanner; public class IfBezBloku2 { public static void main(String[] args) { int licznik, mianownik; System.out.println("Podaj licznik:"); licznik = getInt(); System.out.println("Podaj mianownik:"); mianownik = getInt(); double wynik; if (mianownik != 0) { wynik = licznik / mianownik; System.out.println("Wynik: " + wynik); } } public static int getInt() { return new Scanner(System.in).nextInt(); } }Dzięki 😉
Nie ma za co 🙂