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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
Scanner skaner = new Scanner(System.in); System.out.print("Podaj kariotyp: "); String kariotyp = skaner.nextLine(); System.out.println("Jaki to organizm? (podaj numer)"); System.out.println("1 - ssak, 2 - ryba, 3 - ptak, 4 - motyl, 5 - szczaw "); int organizm = Integer.parseInt(skaner.nextLine()); System.out.println("Organizm: "+organizm+", kariotyp: "+kariotyp); if (kariotyp.equalsIgnoreCase("XX")) { if (organizm == 1) System.out.println("Samica"); else if (organizm == 2) System.out.println("Samiec"); else if (organizm == 3) System.out.println("Samiec"); else if (organizm == 4) System.out.println("Samiec"); else if (organizm == 5) System.out.println("Samica"); else System.out.println("Zły numer organizmu!"); } else if (kariotyp.equalsIgnoreCase("XY")) { if (organizm == 1) System.out.println("Samiec"); else if (organizm == 2) System.out.println("Samica"); else if (organizm == 3) System.out.println("Samica"); else if (organizm == 4) System.out.println("Samica"); else System.out.println("Zły numer organizmu lub kariotyp!"); } else if (kariotyp.equalsIgnoreCase("XYY")) { if (organizm == 5) System.out.println("Samiec"); else System.out.println("Zły numer organizmu lub kariotyp!"); } else System.out.println("Zły numer organizmu lub kariotyp!"); |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
int a = 2; int b = 5; System.out.println("a = "+a+" b = "+b); System.out.println("a < b "+(a<b)); System.out.println("a == b "+(a==b)); System.out.println("a != b "+(a!=b)); System.out.println("a < b && a != b : "+(a<b && a!=b)); System.out.println("a < b && a == b : "+(a<b && a==b)); System.out.println("a > b && a == b : "+(a>b && a==b)); System.out.println("a < b || a != b : "+(a<b || a!=b)); System.out.println("a < b || a == b : "+(a<b || a==b)); System.out.println("a > b || a == b : "+(a>b || a==b)); System.out.println("a < b & a != b : "+(a<b & a!=b)); System.out.println("a < b & a == b : "+(a<b & a==b)); System.out.println("a > b & a == b : "+(a>b & a==b)); System.out.println("a < b | a != b : "+(a<b | a!=b)); System.out.println("a < b | a == b : "+(a<b | a==b)); System.out.println("a > b | a == b : "+(a>b | a==b)); System.out.println("a < b ^ a != b : "+(a<b ^ a!=b)); System.out.println("a < b ^ a == b : "+(a<b ^ a==b)); System.out.println("a > b ^ a == b : "+(a>b ^ a==b)); |
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:
- <, >, <=, >=
- ==, !=
- &&
- ||
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
String allel1, allel2; Scanner skaner = new Scanner(System.in); System.out.print("Podaj pierwszy allel [A/B/0]: "); allel1 = skaner.nextLine(); System.out.print("Podaj drugi allel [A/B/0]: "); allel2 = skaner.nextLine(); if (allel1.equalsIgnoreCase("0") && allel2.equalsIgnoreCase("0")) System.out.println("Grupa krwi: 0"); else if ((allel1.equalsIgnoreCase("A") && allel2.equalsIgnoreCase("B")) || (allel1.equalsIgnoreCase("B") && allel2.equalsIgnoreCase("A"))) System.out.println("Grupa krwi: AB"); 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"); 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"); else System.out.println("Złe dane!"); |
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
You must be logged in to post a comment.