Podejmowanie decyzji z if
Programy muszą reagować na dane: zdany albo niezdany, dostępny albo wyprzedany, poprawny albo nie. Instrukcja if to sposób, w jaki Java wybiera, który kod wykonać na podstawie warunku.
if przyjmuje w nawiasach warunek typu boolean i wykonuje blok w klamrach tylko wtedy, gdy ten warunek ma wartość true:
Warunek score >= 60 ma wartość true, więc komunikat się wypisuje. Wiersz po zamykającej klamrze wykonuje się zawsze, bo jest poza if. Zmień score na 40, a wiersz z „passed” zostanie całkowicie pominięty.
W przeciwieństwie do C Java nie pozwala wstawić liczby tam, gdzie powinna być wartość logiczna. if (score) to błąd kompilacji: warunek musi być prawdziwym wyrażeniem boolean zbudowanym z porównań (>, >=, ==, !=) albo logiki (&&, ||, !).
Dodanie else
else daje ścieżkę „w przeciwnym razie”, czyli kod, który wykonuje się tylko wtedy, gdy warunek ma wartość false:
Wykonuje się dokładnie jeden z dwóch bloków: nigdy oba i nigdy żaden. else nie ma własnego warunku; po prostu łapie wszystko, czego nie złapał if.
Łańcuchy z else if
Gdy możliwych wyników jest więcej niż dwa, połącz warunki za pomocą else if. Java sprawdza je od góry do dołu, wykonuje pierwszy blok, którego warunek jest prawdziwy, i pomija resztę:
Kolejność ma znaczenie. 84 jest najpierw porównywane z >= 90 (fałsz), potem z >= 80 (prawda), więc program zatrzymuje się na B i w ogóle nie sprawdza niższych progów. Dlatego nie musisz pisać score >= 80 && score < 90: dotarcie do drugiej gałęzi już gwarantuje, że score było poniżej 90. Najwęższy albo najważniejszy warunek umieszczaj na początku.
Końcowe else łapie wszystko inne. Pominięcie go tutaj spowodowałoby błąd kompilacji, bo grade mogłoby nie mieć przypisanej wartości w chwili wypisania.
Porównywanie wartości: == a equals()
Najczęstszy błąd w instrukcjach if w Javie to porównywanie napisów przez ==. Dla typów prostych (int, double, char, boolean) == jest poprawne. Dla obiektów == pyta „czy to ten sam obiekt w pamięci?”, a .equals() pyta „czy mają tę samą zawartość?”, i prawie zawsze chodzi ci o to drugie:
Wypisuje się tylko drugi komunikat. new String("yes") to inny obiekt niż literał "yes", więc == daje false, ale tekst jest identyczny, więc .equals() daje true. Prosta zasada: typy proste porównuj przez ==, obiekty przez .equals().
Bezpieczny trik, który chroni przed NullPointerException, gdy zmienna może być null: umieść literał na początku, if ("yes".equals(input)), bo literał nigdy nie jest null.
Łączenie i zagnieżdżanie warunków
Warunki możesz łączyć przez && (i), || (lub) i ! (nie) albo zagnieździć jedno if w drugim, gdy sprawdzenie ma sens dopiero po spełnieniu wcześniejszego:
&& i || działają na skróty: w a && b, jeśli a jest fałszywe, Java w ogóle nie oblicza b. To przydaje się do ochrony przed błędami: if (s != null && s.length() > 0) jest bezpieczne, bo sprawdzenie długości jest pomijane, gdy s to null. Jeśli możesz, łącz warunki przez && zamiast głęboko je zagnieżdżać: płaski kod czyta się łatwiej niż piramidę klamer.
Klasyczna pułapka: pojedyncze = to przypisanie, a == to porównanie. if (x = 5) dla int to błąd kompilacji (i dobrze), ale if (flag = true) dla boolean się kompiluje i po cichu przypisuje wartość. Uważaj na to.
Operator trójargumentowy
Gdy chcesz tylko wybrać jedną z dwóch wartości, operator trójargumentowy ?: załatwia to w jednym wierszu. Czytaj condition ? a : b jako „jeśli warunek, to a, w przeciwnym razie b”:
Operator trójargumentowy zwraca wartość, którą możesz przypisać albo od razu przekazać dalej. Zostaw go do prostego wyboru: jeśli któraś gałąź potrzebuje kilku instrukcji albo prawdziwej logiki, pełne if-else pozostaje czytelne, a zagnieżdżony operator trójargumentowy szybko zamienia się w łamigłówkę.
Pułapka: opcjonalne klamry
Java pozwala pominąć klamry, gdy gałąź ma jedną instrukcję, ale to zaproszenie do subtelnego błędu. Wcięcia kłamią:
if (loggedIn)
System.out.println("Welcome");
System.out.println("Loading dashboard"); // NOT part of the if!
if kontroluje tylko pierwszy wiersz; drugi wykonuje się zawsze, choć wcięcie sugeruje coś innego. Zawsze używaj klamer, nawet dla jednego wiersza, a cała ta kategoria błędów zniknie.
Dalej: switch
Łańcuchy if-else if świetnie sprawdzają się, gdy każda gałąź testuje inny warunek. Gdy jednak porównujesz jedną wartość z wieloma stałymi możliwościami, takimi jak nazwa dnia, wybór z menu albo enum, długa drabinka else if robi się powtarzalna. Instrukcja switch powstała dokładnie do tego i to ją omawia następna strona.
Najczęściej zadawane pytania
Jak napisać instrukcję if-else w Javie?
Umieść warunek logiczny w nawiasach po if, potem kod do wykonania w klamrach i opcjonalny blok else na wypadek, gdy warunek jest fałszywy: if (score >= 60) { System.out.println("Pass"); } else { System.out.println("Fail"); }. Warunek musi dawać wartość boolean: Java nie przyjmie int, jak robi to C.
Czym różni się == od equals() w instrukcji if w Javie?
== sprawdza, czy dwie referencje wskazują ten sam obiekt, a .equals() porównuje zawartość. Dla typów prostych, takich jak int, używaj ==. Dla obiektów, zwłaszcza String, używaj .equals(): if (name.equals("Sam")), a nie if (name == "Sam"). Porównywanie napisów przez == to najczęstszy błąd w instrukcjach if w Javie.
Czym jest operator trójargumentowy w Javie?
Operator trójargumentowy condition ? valueIfTrue : valueIfFalse to zwięzłe if-else, które zwraca wartość. Na przykład String label = age >= 18 ? "adult" : "minor"; przypisuje jedną z dwóch wartości zależnie od warunku. Używaj go do prostego wyboru wartości, a po pełne if-else sięgaj, gdy w każdej gałęzi jest logika do wykonania.