Twitter: @grzegg
Kategoria: java, Tagi: - - .

Java [11] – Operatory logiczne

Operatory logiczne łączą wyrażenia zwracające wartość true lub false co pozwalać bardziej złożone testy prawdziwości, jak na przykład „liczba jest podzielna przez 2 oraz większa niż 10”.

Ta strona jest częścią materiałów do kursu “Programowanie w Javie z elementami bioinformatyki dla poczatkujących”. Pozostałe materiały znajdziesz tutaj

Rozwiązanie zadania z poprzedniej lekcji

Zadanie można rozwiązać na przykład tak:

Być może zastanawiasz się skąd pojawiły się cyfry zamiast pełnych nazw organizmów. Można pytać użytkownika o pełną nazwę ale znacznie lepiej wypisać na ekranie wszystkie możliwości i przypisać do nich odpowiednie liczby/litery. W ten sposób ułatwiamy wybranie opcji i ograniczamy możliwość popełnienia literówki.

Zauważ, że w wielu przypadkach program przeprowadza kilka testów, których pozytywny wynik uruchamia taki sam kod. Na przykład jeśli użytkownik podał kariotyp „XY” to po kolei sprawdzany jest numer przyporządkowany organizmowi i dla wartości 2 lub 3 lub 4 program podaje płeć „Samica”, przy czym dla każdej z tych wartości jest przeznaczona oddzielna linijka kodu z taką samą komendą. Czy nie łatwiej byłby sformułować kodu mniej więcej w ten sposób: „Jeżeli kariotyp wynosi XY ORAZ organizm jest typu 2 LUB 3 LUB 4 to wypisz: Samica”? Właśnie w takich przypadkach przydają się operatory logiczne.

Operatory logiczne

W poniższych tabelach znajdują się dwa podstawowe operatory logiczne (boolowskie) oraz przykładowe wyrażenia z ich udziałem i ich wyniki. Zaraz przyjrzymy się jak działają.

operator znaczenie opis
&& AND (koniunkcja) Zwraca true jeśli oba wyrażenia są prawdziwe.
|| OR (alternatywa) Zwraca true jeśli przynajmniej jedno z wyrażeń jest prawdziwe.
wyrażenie wynik
int x = 5;
x == 5 && x > 0 true
x == 5 || x > 0 true
x == 5 && x < 0 false
x == 5 || x < 0 true

Wyniki działania operatorów na wartościach true i false można przedstawić w bardziej ogólnej postaci:

wartość 1 wartość 2 operator wynik
true true && true
true false && false
false false && false
true true || true
true false || true
false false || false

Podobne działania do powyższych mają operatory logiczne & oraz |. Mają one zresztą szersze zastosowanie, które tu pominiemy. Biorąc pod uwagę ich przydatność w tworzeniu warunków w konstrukcjach typu if najistotniejsza różnica pomiędzy omawianymi dwuznakowymi i jednoznakowymi operatorami polega na tym, że w wymienionych jednoznakowych (tzw. zachłannych) operatorach zawsze ewaluowane są oba wyrażenia połączone operatorem natomiast w dwuznakowych (tzw. leniwych) tylko wtedy oba są ewaluowane, jeśli to jest konieczne. Zauważ, że jeśli mamy operator && to zostanie zwrócona wartość true tylko wtedy jeśli oba wyrażenia (po prawej i po lewej stronie) zwrócą wartości true. Jeśli więc pierwszy test zwróci wartość false nie ma sensu sprawdzać drugiego. Może się wydawać, że ma to znaczenie wyłącznie dla poprawiania wydajności kodu. Ale przyjrzyj się takiej linii kodu:


if (x > 0 & y/x > 1) {
...
}

Co się stanie, jeżeli x jest równe 0? Przy użyciu operatora & zostaną sprawdzone oba wyrażenia, dojdzie więc do próby podzielenia y przez 0 co spowoduje błąd. Jeśli natomiast zastosujemy operator &&:


if (x > 0 && y/x > 1) {
...
}

to po zwróceniu przez porównanie x > 0 wartości false, nie zostanie już sprawdzony warunek po prawej stronie, nie dojdzie więc do próby wykonania błędnej matematycznie operacji.

Warto jeszcze wspomnieć o jednym operatorze logicznym: ^ nazywanym XOR (alternatywa wykluczająca) który zwraca wartość true wtedy, gdy tylko jeden z argumentów ma wartość true a drugi false (kolejność jest obojętna). Zastanów się, dlaczego nie ma operatora ^^.

Poniższy kod ilustruje działanie omawianych operatorów:

W dalszej części skupimy się na operatorach && oraz ||.

Priorytety operatorów

Podobnie jak w matematyce (np. mnożenie przed dodawaniem), także w programowaniu należy brać pod uwagę priorytety operatorów.
Poznane dotychczas operatory można uporządkować, w porządku od tych z najwyższym priorytetem:

  1. <, >, <=, >=
  2. ==, !=
  3. &&
  4. ||

Domyślne priorytety operatorów niekoniecznie muszą odpowiadać temu co chcemy, żeby komputer zrobił. Na przykład w rachunkach 2 + 4 * 2 to nie to samo co (2 + 4) * 2.
Ponadto często chcemy połączyć różnego rodzaju porównania w dość skomplikowany układ warunków, który powinien być rozpatrywany w określonej kolejności. Możemy sobie pomóc używając nawiasów. Ma to znaczenie także dla przejrzystości kodu.

Przykład

Napisz aplikację, która określa grupę krwi (A, B, 0) na podstawie dostarczonego genotypu (użytkownik podaje osobno dwa allele).

Jak wiadomo grupa krwi w systemie A, B, 0, zależy od genu który w populacji ludzkiej występuje w postaci trzech alleli: IA, IB, i0
Tabela pokazuje jakie genotypy odpowiadają poszczególnym grupom krwi:

grupa krwi genotypy
AB IA iB
A IA IA, IA i0
B IB IB, IB i0
0 i0 i0

Dla uproszczenia, allele przy wprowadzaniu oznaczymy jako A, B, 0
Użytkownik wprowadzi w konsoli najpierw jeden (zmienna allel1), a później drugi allel (zmienna allel2)
Trzeba wziąć pod uwage, że kolejność wprowadzonych alleli może być dowolna (allel1=”A”, allel2=”0″ jest równoważne allel1=”0″, allel2=”A”), genotypy IA i0 oraz i0 IA są przecież tożsame.

grupa krwi genotypy układy zmiennych
AB IA iB A B, B A
A IA IA, IA i0 A A, A 0, 0 A
B IB IB, IB i0 B B, B 0, 0 B
0 i0 i0 0 0

Zaprojektujmy ogólną konstrukcję programu używając pseudokodu:


Pobierz dane
Jeśli (warunek na grupę krwi AB) to wypisz „Grupa AB”
Jeśli (warunek na grupę krwi A) to wypisz „Grupa A”
Jeśli (warunek na grupę krwi B) to wypisz „Grupa B”
Jeśli (warunek na grupę krwi 0) to wypisz „Grupa 0”
Jeśli żaden z powyższych to Wypisz „Złe dane!”

Zastosujemy konstrukcję: if ... else if ... else ...

Kluczową sprawą jest teraz prawidłowe sformułowanie warunków dla poszczególnych grup krwi

Zacznijmy od najprostszej grupy 0:
Pierwszy allel musi być 0 i drugi allel musi być 0:


if (allel1.equalsIgnoreCase("0") && allel2.equalsIgnoreCase("0"))

System.out.println("Grupa krwi: 0");

Teraz AB:
Pierwszy allel musi być A i drugi B, lub pierwszy B i drugi A


else if ((allel1.equalsIgnoreCase("A") && allel2.equalsIgnoreCase("B")) ||

(allel1.equalsIgnoreCase("B") && allel2.equalsIgnoreCase("A")))

System.out.println("Grupa krwi: AB");

Teraz grupa A:
Pierwszy allel A i drugi allel A lub pierwszy allel A i drugi allel 0 lub
pierwszy allel 0 i drugi allel A:


else if ((allel1.equalsIgnoreCase("A") && allel2.equalsIgnoreCase("A")) ||
(allel1.equalsIgnoreCase("A") && allel2.equalsIgnoreCase("0")) ||
(allel1.equalsIgnoreCase("0") && allel2.equalsIgnoreCase("A")))
System.out.println("Grupa krwi: A");

Grupa B analogicznie do A:
Pierwszy allel B i drugi allel B lub pierwszy allel B i drugi allel 0 lub
pierwszy allel 0 i drugi allel B:


else if ((allel1.equalsIgnoreCase("B") && allel2.equalsIgnoreCase("B")) ||
(allel1.equalsIgnoreCase("B") && allel2.equalsIgnoreCase("0")) ||
(allel1.equalsIgnoreCase("0") && allel2.equalsIgnoreCase("B")))
System.out.println("Grupa krwi: B");

i w końcu:


else System.out.println("Złe dane!");

Pełny kod:

Zadanie

Poprawić program rozpoznawania płci po chromosomach (z prezentacji dot. instrukcji wyboru) grupując warunki z użyciem poznanych operatorów logicznych.

Ta strona jest częścią materiałów do kursu “Programowanie w Javie z elementami bioinformatyki dla poczatkujących”. Pozostałe materiały znajdziesz tutaj

Leave a Reply