1. Wyrażenia vs instrukcje
Wszystkie konstrukcje w Javie dzielą się na dwie kategorie: instrukcje (Statement) i wyrażenia (Expression). O instrukcji mówi się, że jest wykonywana, a o wyrażeniu — że jest obliczane. Ale to nie jest najważniejsze.
Główna różnica między instrukcją a wyrażeniem polega na tym, że wyrażenie ma wynik obliczenia. Ten wynik ma po pierwsze typ, a po drugie można go gdzieś przypisać albo użyć w innym wyrażeniu.
Przykłady:
| Kod | Uwagi |
|---|---|
|
Instrukcja |
|
Wyrażenie, typ boolean |
|
Wyrażenie, typ taki jak typ zmiennej i |
|
Wyrażenie, typ taki jak typ zmiennej x |
I co nam to daje?
Po pierwsze, możemy wykorzystać fakt, że bardzo wiele instrukcji w rzeczywistości jest wyrażeniami (mają wynik obliczenia). Na przykład taki kod zadziała:
int x, y, z;
x = y = z = 1; // x = (y = (z = 1));
Po drugie, możemy zignorować wynik obliczenia wyrażenia, jeśli chcemy.
console.nextLine(); // ignorujemy wynik wczytania
Ignorowanie wyniku obliczenia wyrażenia ma sens np. wtedy, gdy oprócz wyniku wyrażenie wykonuje coś pożytecznego i to działanie jest dla nas ważne, a sam wynik — nie.
2. Operator warunkowy (trójargumentowy)
Ten trik jest ciekawszy od poprzedniego. W Javie istnieje specjalny operator warunkowy (trójargumentowy). Przypomina skróconą formę instrukcji if–else:
Warunek ? Wyrażenie1 : Wyrażenie2;
Jeśli warunek jest prawdziwy, wybierane jest wyrażenie1, w przeciwnym razie wybierane jest wyrażenie2. Po warunku stoi znak zapytania, a dwa wyrażenia są rozdzielone dwukropkiem.
Główna różnica operatora warunkowego od instrukcji if-else polega na tym, że operator warunkowy jest wyrażeniem, a więc jego wynik można przypisać.
Na przykład chcemy obliczyć minimum z dwóch liczb. Z użyciem operatora warunkowego kod będzie wyglądał tak:
int a = 2;
int b = 3;
int min = a < b ? a : b;
Albo załóżmy, że trzeba przypisać zmiennej różne wartości w zależności od jakiegoś warunku. Jak to zrobić?
Wariant pierwszy – użyć instrukcji if-else:
int age = 25;
int money;
if (age > 30)
money = 100;
else
money = 50;
Wariant drugi – użyć operatora warunkowego, czyli skróconej formy instrukcji if-else:
int age = 25;
int money = age > 30 ? 100 : 50;
Czego zatem lepiej użyć: if-else czy operatora warunkowego? Pod względem szybkości wykonania większej różnicy nie ma. To raczej kwestia czytelności kodu. I to bardzo ważne: kod powinien nie tylko działać poprawnie, ale też być łatwy do czytania przez innych programistów.
Najprostsze kryterium może być takie: jeśli kod mieści się w jednym wierszu – użyj operatora warunkowego; jeśli w jednym wierszu już się nie mieści – lepiej użyć if-else.
3. Niuanse działania
Typy wartości
Ważne, aby pamiętać: obie gałęzie operatora warunkowego (<wartość_jeśli_prawda> i <wartość_jeśli_fałsz>) muszą mieć ten sam typ albo być zgodne (np. oba String albo oba int).
Działa:
int a = 10, b = 20;
int max = (a > b) ? a : b; // obie gałęzie — int
Błąd kompilacji:
int a = 10, b = 20;
// String i int są niezgodne
String result = (a > b) ? "większe" : 0; // Błąd kompilacji: nie można przypisać wartości int do zmiennej typu String
Poprawny wariant:
int a = 10, b = 20;
String result = (a > b) ? "większe" : "mniejsze lub równe";
Przykład: praca z liczbami
Policzmy wartość bezwzględną za pomocą operatora warunkowego:
int number = -5;
int abs = (number >= 0) ? number : -number;
System.out.println(abs); // 5
4. Wbudowanie operatora warunkowego w aplikację
Napiszmy proste aplikacyjne okno dialogowe: oprócz przywitania program powie użytkownikowi, ile lat będzie miał za rok, i wskaże, czy będzie pełnoletni.
System.out.print("Podaj swoje imię: ");
String name = console.nextLine();
System.out.print("Podaj swój wiek: ");
int age = console.nextInt();
int nextYear = age + 1;
String status = (nextYear >= 18) ? "pełnoletni" : "niepełnoletni";
System.out.println("Cześć, " + name + "! W przyszłym roku będziesz mieć " + nextYear + ". Będziesz " + status + ".");
Wyjaśnijmy szczegóły:
Zmienna status jest wyliczana przez operator warunkowy: jeśli wiek za rok będzie co najmniej 18, użytkownik będzie pełnoletni (albo pozostanie takim).
5. Zagnieżdżone operatory warunkowe — ostrożnie!
Operator warunkowy można zagnieżdżać (w każdej z gałęzi może być kolejny). Ale… od tego zwykle boli głowa, zwłaszcza tego, kto będzie czytał kod po tobie (nawet jeśli to ty za 2 dni).
Przykład: określenie kategorii na podstawie wieku
String category = (age < 7) ? "przedszkolak" :
(age < 18) ? "uczeń" :
(age < 65) ? "dorosły" : "emeryt";
Tabela podejmowania decyzji:
| Wiek | Warunek | Wynik |
|---|---|---|
| < 7 | |
przedszkolak |
| 7–17 | |
uczeń |
| 18–64 | |
dorosły |
| 65 i więcej | w przeciwnym razie | emeryt |
Taki kod da się jeszcze czytać, ale jeśli logika jest bardziej złożona — lepiej użyć if-else if-else.
6. Lifehack: operator warunkowy i typ boolean
Czasami chcemy napisać wyrażenie w stylu:
boolean adult = (age >= 18) ? true : false;
Ale to jest zbędne. Samo wyrażenie (age >= 18) już zwraca boolean. Dlatego można to skrócić do:
boolean adult = (age >= 18);
GO TO FULL VERSION