1. Wprowadzenie
Zacznijmy od prostej analogii. Wyobraź sobie przepis:
Wymieszaj mąkę, jajka i cukier, ubij, dodaj masło, ubij ponownie.
Brzmi dziwnie? A teraz wyobraź sobie, że między słowami „ubij” i „dodaj” stoi przecinek lub nawias. Kolejność czynności od razu staje się jaśniejsza.
W programowaniu podobna sytuacja pojawia się, gdy piszesz złożone wyrażenie:
boolean result = a > 0 && b < 10 || c == 3;
Jaka jest kolejność? Co zostanie obliczone najpierw: a > 0 && b < 10, a potem || c == 3? Czy może odwrotnie?
Bez jednoznacznej kolejności obliczeń komputer może „pomieszać składniki”, a wynik będzie nieoczekiwany.
2. Priorytet operatorów w Java
Java (podobnie jak większość języków programowania) używa określonej tabeli priorytetów operatorów.
Operatory o wyższym priorytecie wykonywane są wcześniej niż operatory o niższym priorytecie.
Spójrz na najważniejszą część tej tabeli (dla wyrażeń warunkowych):
| Operator | Opis | Priorytet |
|---|---|---|
|
Nawiasy | najwyższy |
|
Logiczne „NIE” | wysoki |
|
Równe / różne | średni |
|
Porównania | średni |
|
Logiczne „I” | niższy |
|
Logiczne „LUB” | jeszcze niższy |
(Są też operatory arytmetyczne — mają wyższy priorytet niż logiczne.)
Najważniejsza zasada
Operatory „I” (&&) mają wyższy priorytet niż „LUB” (||),
czyli najpierw zostanie obliczone „I”, a potem „LUB”. Nie bez powodu I to logiczne mnożenie, a LUB — dodawanie.
Schemat blokowy obliczania priorytetu warunków
graph LR
A["a > 0"] --&&--> B["b < 10"]
B --||--> C["c == 3"]
(W praktyce: a > 0 && b < 10 || c == 3 — najpierw obliczane jest a > 0 && b < 10, a następnie wynik łączony z c == 3 przez ||.)
3. Kierunek łączenia operatorów: od lewej do prawej i odwrotnie
Oprócz priorytetu jest jeszcze takie pojęcie: asocjatywność.
To reguła określająca, w jakim kierunku są obliczane operatory, gdy stoją „obok siebie” i mają ten sam priorytet.
Przykład:
boolean a = true, b = false, c = true;
boolean result = a && b && c;
Pytanie: jak to zostanie policzone?
Odpowiedź: asocjatywność dla && — od lewej do prawej.
Zatem najpierw a && b, a potem wynik z c.
W odniesieniu do warunków:
| Operator | Asocjatywność |
|---|---|
|
od lewej do prawej |
|
od prawej do lewej |
4. Nawiasy — twój najlepszy przyjaciel w złożonych warunkach
Tu zaczyna się magia (i ratunek). Gdy piszesz wyrażenie, nawiasy zmieniają priorytet i czynią kod bardziej czytelnym oraz bezpieczniejszym.
Przykład 1 (bez nawiasów):
// Chcemy: "Jeśli użytkownik jest dorosły i obywatelem, albo jeśli ma przepustkę specjalną"
boolean isAdult = age >= 18;
boolean isCitizen = country.equals("Białoruś");
boolean hasPermit = hasSpecialPass == true;
if (isAdult && isCitizen || hasPermit)
{
System.out.println("Dostęp przyznany!");
}
Jak liczy Java:
Najpierw oblicza isAdult && isCitizen, a potem wynik łączy operatorem || z hasPermit.
- Załóżmy, że isAdult = true, isCitizen = false, hasPermit = true
- isAdult && isCitizen → true && false → false
- false || true → true
Czyli jeśli ktoś ma przepustkę specjalną, i tak zostanie przepuszczony.
A jeśli nie ma przepustki, ale jest dorosłym obywatelem — również zostanie przepuszczony.
Przykład 2 (z nawiasami):
if (isAdult && (isCitizen || hasPermit))
{
System.out.println("Dostęp przyznany!");
}
Teraz program najpierw sprawdza: isCitizen || hasPermit, a następnie ten wynik razem z isAdult.
Czyli musisz być dorosłym i (albo obywatelem, albo mieć przepustkę specjalną).
Drobna różnica w nawiasach — ogromna różnica w logice!
GO TO FULL VERSION