2. Operatory i wyrażenia porównania
W wielu instrukcjach sterujących będą występować warunki podane jako wyrażenie relacyjne, konstruowane z zastosowaniem operatorów relacyjnych oraz operatorów równości - nierówności.
Np. w nawiasach instrukcji if występuje warunek, który może być takim wyrażeniem:
if (a > b) ...
Po części już omawialiśmy te operatory. Warto jednak usystematyzować podane wcześniej informacje oraz uzupełnić je o nowe fakty.
Operatory relacyjne (<, <=, >, >=):
- są operatorami dwuargumentowymi
- ich argumentami mogą być wyłącznie wyrażenia typów numerycznych (byte, char, short, int, long, float, double)
- wyrażenia relacyjne (konstruowane z pomocą tych operatorów) dają zawsze w wyniku wartości typu boolean (true lub false)
Operatory relacyjne
| Wyrażenie
(a i b - dowolne wyrażenia,
ale koniecznie
typu numerycznego)
| Wynik
| a > b
| true jeśli wartość a jest większa od b
false w przeciwnym razie
| a >= b
| true jeśli wartość a jest większa lub równa b
false w przeciwnym razie
| a < b
| true jeśli wartość a jest mniejsza od b
false w przeciwnym razie
| a <= b
| true jeśli wartość a jest mniejsza lub równa b
false w przeciwnym razie
|
Przykłady:
int a =1, b = 3;
if (a > b) System.out.println("Większe");
else System.out.println("Mniejsze");
| Wyprowadzi napis:
Mniejsze
| int a =1, b = 3;
if (a + 1 > b/3) System.out.println("Większe");
else System.out.println("Mniejsze");
uwaga: priorytet operatorów relacyjnych jest niższy od priorytetu operatorów arytmetycznych - dzięki temu nie musimy pisać:
if ( (a + 1) > (b/3) ) ...
| Wyprowadzi napis:
Większe
| int a = 1, b = 3;
boolean wynik1 = a <= b;
boolean wynik2 = 1 >= a;
boolean wynik3 = a < 1;
uwaga: priorytet operatorów relacyjnych jest wyższy od priorytetu operatora przypisania - dzięki temu nie musimy pisać:
boolean wynik = (a <= b);
| Zmienne będą miały następujące wartości:
wynik1 == true
wynik2 == true
wynik3 == false
|
Częstym błędem jest stosowanie zamiast operatora równości == znaku =.
Należy się go wystrzegać, choć zwykle kompilator wykryje ten błąd i zwróci
nam na niego uwagę.
Od grupy operatorów relacyjnych odróżnia się dwuargumentowe operatory równości (==) i nierówności (!=) - z dwóch powodów:
- mają one niższy priorytet niż operatory relacyjne
- ich argumentami mogą być wartości wszystkich typów (numerycznych, logicznych, referencyjnych), pod warunkiem jednak, że:
- jeżeli jeden z argumentów jest typu numerycznego - to drugi też musi być typu numerycznego,
- jeżeli jeden z argumentów jest typu boolean - to i drugi musi być tego typu,
- jeżeli jeden z argumentów jest typu referencyjnego, to drugi musi
być typu referencyjnego dającego się przekształcić do typu pierwszego albo
literałem null (o przekształceniach typów będziemy mówić później;
na razie możemy przyjąć, że obowiązuje nas ograniczenie porównywania na równość
- nierówność tych samych typow referencyjnych np. referencji typu String
lub referencji typu Para)
Konstruowane za pomocą operatorów równości-nierówności wyrażenia mają zawsze wynik typu boolean.
Operatory równości - nierówności
| Wyrażenia
| a == b
| a != b
| a i b dowolnego typu numerycznego
| true jeśli wartość a jest równa wartości b false w przeciwnym razie
| true jeśl
i wartość a nie jest równa wartości b false w przeciwnym razie
| a i b typu boolean
| true jeśli a i b oba mają wartość true lub wartość false false w przeciwnym razie
| true jeśli a jest true, b false lub odwrotnie false, jeśli a i b są oba true lub oba false
| a i b typu referencyjnego
| true jeśli obie referencje wskazują
ten sam obiekt lub jeśli obie mają wartość null false jeśli referencje odnoszą się do różnych obiektów, lub jedna z nich ma wartość null, a druga - nie
| true jeśli obie referencje odnoszą się do innych obiektów lub jeśli jedna z nich jest null, a druga nie false jeśli obie referencje wskazują ten sam obiekt lub jeśli obie mają wartość null
|
Przykład:
int a = 2, b = a + 1;
if ( a == b) System.out.println("tak");
else System.out.println("nie");
if ( a != --b) System.out.println("tak"); // 2
else System.out.println("nie");
int c = 4;
if ( a < b + 1 == b < c) System.out.println("tak"); //3
else System.out.println("tak");
nie
nie
tak
Ten fragment kodu wypisze na konsoli dane podane obok.
Uwagi:
- przedrostkowa forma operatora -- zapewnia, że wartość b w przykładzie
2 będzie zmieniona przed użyciem w wyrażeniu porównania na nierówność;
-
w przykładzie 3 korzystamy z tego, że priorytet operatora == jest niższy od
priorytetu operatorów relacyjnych, a te z kolei są niższe od priorytetów operatorów
arytmetycznych (+); na równość porównywane są zatem dwie wartości typu boolean,
a ponieważ obie są true, to wynik porównania też jest true
Jednak - w zasadzie nie należy zapisywać w taki sposób jak w przykładzie
oznaczonym // 3 złożonych wyrażeń. Raczej warto użyć nawiasów, które zwiększą
czytelność kodu.
Zresztą porównywanie wartości boolowskich jest mało użyteczne, bo - w większości
przypadków - zamiast niego należy stosować logiczne operatory koniunkcji
czy alternatywy.
Przykład porównywania referencji:
// Klasa Para - to znana nam już klasa par liczb całkowitych
Para p1 = new Para(1,1);
Para p2 = new Para(1,1);
Para p3 = p1;
p1 == p2 // false, mimo że składniki par są takie same
p1 == p3 // true, bo wskazują na ten sam obiekt
String s1 = "1,1";
p1 == s1 // bląd w kompilacji, bo p1 jest typu Para, a s1 typu String
String s2 = "1," + 1;
s1 == s2 // false, bo są to referencje do różnych obiektów
s1 == null // false, bo s1 wskazuje na jakiś obiekt
s1.equals(s2) // true, bo zawartość łańcuchów znakowych jest taka sama.
Przypomnienie: porównywanie zawartości obiektów (na równość - nierówność)
odbywa się zawsze za pomocą metody equals, zdefiniowanej w klasie obiektów.
Uwaga: W przeciwieństwie do klasy String, w klasie Para nie zdefiniowano
metody equals. Jej użycie nie da zatem spodziewanych efektów. Tego w jaki
sposób definiować metodę equals we własnych klasach - dowiemy się w przyszłym
semestrze, wymaga to bowiem nieco bardziej zaawansowanej wiedzy "obiektowej",
m.in. rozumienia pojęcia polimorfizmu.
Na koniec omawiania porównań warto zwrócić uwagę na liczby rzeczywiste. Otóż wszystkie porównania są zawsze dokładne. Ale reprezentacja liczb rzeczywistych w komputerze nie jest dokładna. Dlatego przy porównaniu liczb rzeczywistych powinniśmy sprawdzać nie tyle
czy są one dokładnie równe, ale czy ich wartości są dostatecznie sobie bliskie.
Więcej o tym w wykładzie o liczbach.
|