Kolejnym tematem z Javy wymagającym nadrobienia zaległości są operatory. Operatory w języku Java jak najbardziej wymagają stosu komentarzy, abyś mógł/mogła programować w sposób świadomy. Zaczynamy!
Tweet |
OPERATORY W JĘZYKU JAVA NIE ODSTAJĄ NICZYM OD (WIĘKSZOŚCI) INNYCH JĘZYKÓW
Niech za dowód posłuży choćby C# i Kotlin, o których już napisałem całą litanię jakiś czas temu. Operator jest po prostu znakiem z klawiatury nadającym pewne znaczenie dla jego argumentów "położonych" obok niego, czyli operandów. Operandem może być na przykład liczba 16.
Część operatorów wymaga innej liczby operandów niż reszta i to zależy od kontekstu co konkretnie chcemy zrobić. Jeśli chcemy zsumować ze sobą dwie liczby, to jasnym jest, że wstawiamy operator plusa (+), a po obu stronach dajemy jakąś liczbę. Operatory w języku Java (jak zresztą w całej gamie innych języków programowania) przypominają układankę, w której jeden element nadaje całości inne znaczenie. Zmieniając operator dodawania na operator mnożenia (*), uzyskujemy iloczyn i tak dalej.
Nadszedł czas zapoznać się ze wszystkimi rodzajami operatorów z jakich możecie skorzystać w języku Java!
ARYTMETYCZNE
Arytmetyka jaka jest, każdy widzi. Zestaw operatorów pozwalających na otrzymanie wyniku liczbowego w wyniku wstawienia dwóch / więcej liczb. Liczby mogą być całkowite i zmiennoprzecinkowe (z ułamkiem) oraz dozwolone jest łączenie jednego typu z drugim. O typach danych jest w innym materiale. Wymieńmy sobie po kolei operatory arytmetyczne:
DODAWANIE
Pierwsze znaczenie, sumowanie liczb. Odkąd istnieje matematyka, tak do tej pory używamy plusika (+) do oznaczenia, że chcemy zsumować dwie / więcej liczb 😉. To jest operator dwuargumentowy, to znaczy że operacja sumowania bez podania dwóch liczb po obu stronach okaże się niemożliwa do dopuszczenia przez kompilator:
52 + // bzdura!
+52 // bzdura!
52 + 8 // OK, całkowita + całkowita
52 + 8.7 // OK, całkowita + zmiennoprzecinkowa
52 + 8.7 + 3.1 // OK, całkowita + zmiennoprzecinkowa + zmiennoprzecinkowa
Nawet jeśli dodajecie do siebie więcej liczb, to i tak operator pozostaje dwuargumentowym, bo dla każdego nowego składnika musicie wstawić nowy znak plusa. Nawiasem pisząc, obowiązuje w kodzie źródłowym notacja amerykańska. To znaczy, że oddzielacie część ułamkową używając kropki, a nie przecinka!
Drugie znaczenie, konkatenacja łańcuchów znaków. Konkatenacja to operacja łączenia wielu łańcuchów znaków / wyrażeń arytmetyczny w jeden "połączony" łańcuch znaków. Jak już wiemy z artykułu wprowadzającego do języka Java, łańcuch znaków wcale nie musi być tekstem. To może być dowolny ciąg, w tym również wynik wyrażenia arytmetycznego:
"Wynik: " + (52 + 8) // OK, konkatenacja łańcucha znaków z wyrażeniem arytmetycznym
"Java" + " przyda" + " mi" + " się" + " w" + " życiu." // OK, konkatenacja samych łańcuchów znaków
Zwróć uwagę na wystające spacje w łańcuchach znaków! Bez nich, słowa połączyłyby się w jedno hasło.
ODEJMOWANIE
Znak minusa przed liczbą (-) oznaczać może dwie rzeczy: albo chcemy odjąć jedną od drugiej, albo oznaczyć że dana liczba ma być ujemna. Nie wszystkie operatory w języku Java muszą mieć koniecznie dwie liczby obok siebie. Stąd może to być operator przyjmujący jeden argument (operator unarny) albo dwa argumenty. Oczywiście w przypadku pojedynczej liczby, minus musi znajdować się za nią, bo ciężko sobie wyobrazić inną kombinację 😂:
52 - // bzdura!
-52 // OK, operator unarny wykonujący przypisanie liczby ujemnej
52 - 5 // OK, operator binarny (dwuargumentowy) wykonujący operację różnicy
MNOŻENIE
Iloczyn może zostać przeprowadzony przy użyciu co najmniej dwóch liczb, zatem możemy rozmawiać wyłącznie o operatorze dwuargumentowym:
52* // bzdura!
52*8.5 // OK
Innych zastosowań nie ma. Mnożenie przeprowadzamy za pomocą znaku gwiazdki (*), choć fachowa nazwa brzmi "asterysk". Od siebie dorzucą małą rekomendację w sprawie formatowania kodu, żeby operatora iloczynu nie oddzielać od operandów spacją. Tak jest znacznie czytelniej.
DZIELENIE
Czwartą podstawową operacją jest słynny iloraz, czyli dzielenie liczb przez siebie. Kombinacje mogą być różne:
52 / 6 // OK
52 / 3.5 // OK
52 / 3 / 2 // OK
52 / 0 // zgłoszenie wyjątku!
Jednak zrobię przystanek przy ostatnim przypadku. Jak dobrze wiecie, dzielenie przez zero jest kompletnym nonsensem. Gdy spróbujesz wykonać takie działanie, program zostanie brutalnie przerwany, a instrukcja zgłosi wyjątek "DivideByZeroException"!!! Wyjątki są szczegółowo opisane w odrębnym materiale i radzę go przeczytać dopiero po zgromadzeniu wiedzy z bardziej podstawowych tematów.
Druga ważna rzecz. Operator dzielenia zwraca wynik całkowitoliczbowy albo zmiennoprzecinkowy w zależności od typów operandów. W trzecim przykładzie mamy trzy operandy całkowitoliczbowe:
52 / 3 / 2
co da taki skutek, że najpierw 52 zostanie podzielone przez 3 i wynikiem będzie 17 bez ułamka, a potem to 17 dzielimy przez 2 i uzyskujemy wynik 8, znowu bez ułamka!!! Ale dlaczego???
Nie wszyscy o tym wiedzą, że iloraz całkowitoliczbowy zaokrągla zawsze liczbę w dół co nazywane jest "obcinaniem". Wypowiedziałem się już w tej sprawie, więc zainteresowanych odsyłam do odpowiedniego materiału.
RESZTA Z DZIELENIA (MODULO)
Operacja modulo również składa się na podstawowe operatory w języku Java. Wystarczy że streszczę jak to działa bowiem osobny artykuł na ten temat został już opracowany. Pozwala to na otrzymanie reszty z dzielenia dwóch liczb, najczęściej całkowitych choć mogą to być zmiennoprzecinkowe. Jego znakiem rozpoznawczym jest symbol procent (%), który także jest jedynie operatorem dwuargumentowym:
5 % // bzdura!
5 % 2 // OK, 2 reszty 1
To, co jest po słowie "reszty", to staje się wynikiem operacji modulo.
INKREMENTACJA / DEKREMENTACJA
Ostatni przypadek jaki mógł polecieć pod skrzydła dodawania i odejmowania, jednak chciałem to wyróżnić. Bardzo często na swojej drodze spotkasz się z terminami inkrementacji i dekrementacji. Jednym zdaniem, to służy do dodawania lub odejmowania od liczby o 1, jednak tylko w przypadku liczb całkowitych! Ponadto jest podział na następujące operacje:
- preinkrementacja,
- predekrementacja,
- postinkrementacja,
- postdekrementacja.
Dla inkrementacji stosujemy dwa znaki plusa (++), a dwa znaki minusa (--) oznaczają dekrementację:
int i = 0;
++i; // preinkrementacja
--i; // predekrementacja
i++; // postinkrementacja
i--; // postdekrementacja
JEST różnica pomiędzy "pre", a "post" i staje się widoczna podczas programowania pętli i tablic, zatem przeczytaj koniecznie ten artykuł i ten, bo tam opisuję przypadek kiedy to wyraźnie widać. Króciutko opisując, to decyduje o kolejności odczytywania i modyfikowania wartości. Przy "pre", najpierw jest modyfikacja a potem odczyt, a "post" opóźnia modyfikację nadając priorytet operacji odczytu.
Inkrementację i dekrementację stosuje się zazwyczaj w stosunku do zmiennych, czyli obiektów danych przechowujących daną wskazanego typu. Zmienne zostały opisane w innym artykule.
RELACYJNE
Zmęczeni materiałem? To dopiero początek 😄! Operatory w języku Java to nie tylko arytmetyka! Są również operatory relacyjne służące do badania zdań logicznych celem zwrócenia jednego z dwóch wyników: zdanie jest prawdziwe ("true") albo fałszywe ("false"). Zdania logiczne są reprezentowane przez logiczny typ danych nazywanych w Javie "boolean". Tabelka w ruch:
OPERATOR | ZNACZENIE |
== | równe |
!= | różne od |
> | większe od |
>= | większe bądź równe od |
< | mniejsze od |
<= | mniejsze bądź równe od |
Wszystkie wyżej wymienione operatory są dwuargumentowymi. Operatory relacyjne pozwalają na porównywanie ze sobą liczb, łańcuchów, obiektów (tylko ==), jeżeli oczywiście nasze intencje będą sensowne i nie będziemy próbować na siłę sprawdzić czy liczba jest większa od obiektu.
Trzeba jeszcze zwrócić Waszą uwagę na to, żeby broń Boże nie mylić porównania (==) z przypisaniem (=)!!! Operator przypisania służy do przypisywania wartości zmiennym, a operator porównywania do porównywania ze sobą wartości (albo zmiennych). Pierwszy reprezentuje jeden znak równości, drugi dwa. Zapamiętaj!
LOGICZNE
Kolejne operatory w języku Java to są logiczne. Wykorzystujemy je także celem otrzymania odpowiedzi zwrotnej w postaci wartości logicznej (coś jest prawdą albo fałszem). W celu ich prawidłowego użycia, łączymy je z operatorami relacyjnymi i taki miks osadzamy do instrukcji warunkowej (temat na osobny artykuł, kochani!):
OPERATOR | ZNACZENIE |
&& | koniunkcja, operator AND |
|| | alternatywa, operacja OR |
^ | alternatywa wykluczająca (rozłączna), operacja XOR |
! | negacja, operacja NOT |
W tabelce zostawiłem odnośnik do każdego z rodzajów opisujący dużo szerzej do czego one służą. Tutaj tylko krótko jednym zdaniem.
KONIUNKCJA
Koniunkcja (iloczyn logiczny) zwraca prawdę wtedy i tylko wtedy, gdy wszystkie zdania są prawdziwe:
boolean b = (5 == 5 && 6 > 4);
5 jest równe 5, a 6 jest większe od 4, zatem to zdanie jest prawdziwe! Znak koniunkcji to podwójny znak ampersandu (&&).
ALTERNATYWA
Suma logiczna nazywana alternatywą potrzebuje tylko, żeby DOWOLNE zdanie było prawdziwe i całe zdanie okaże się prawdziwe:
boolean b = (7 < 3 || 4 >= 4);
7 nie jest mniejsze od 3, zatem to zdanie jest fałszywe, ale widać drugie sprawdzenie, które jest już spełnione (4 jest równe 4). Zatem, zmienna "b" przyjmie wartość "true". Dwie pionowe kreseczki (||) oznaczają znak alternatywy.
ALTERNATYWA WYKLUCZAJĄCA (ROZŁĄCZNA)
Inną odmianą alternatywy jest alternatywa rozłączna, zwana też wykluczającą albo można ją też określić sumą poprzeczną. Chodzi o zwrócenie zdania prawdziwego, tylko gdy NIEPARZYSTA liczba warunków jest spełniona. Widzisz to? Nieparzysta!
boolean b = (5 < 2 ^ 6 == 6 ^ 2 != 2);
To zwróci prawdę. A wiesz dlaczego? Ponieważ tylko drugi warunek będzie spełniony! 1 / 3, zatem liczba spełnionych warunków jest nieparzysta. "Dzióbek" (^) definiuje alternatywę rozłączną.
NEGACJA
Negacja jest wyjątkiem od innych, gdyż to jest jedyny operator akceptujący tylko jeden argument tzw. operator unarny. Jego zadaniem jest odwrócenie wyniku zdania logicznego:
boolean b = !(5 == 6);
Czy zdanie jest fałszywe? Byłoby, gdyby nie znak wykrzyknika (!) przed wyrażeniem porównującym, który określa negację.
BITOWE
Bitowe operatory w języku Java stanowią następną kategorię z jaką trzeba Was zapoznać (więcej informacji znajdziesz tutaj). Jak sama nazwa wskazuje, pozwalają one na modyfikowanie wartości operując na bitach w systemie binarnym. Można je zastosować tylko w stosunku do liczb całkowitych ("int")! Oto one:
OPERATOR | ZNACZENIE |
& | koniunkcja bitowa |
| | alternatywa bitowa |
^ | bitowa alternatywa wykluczająca |
~ | negacja bitowa |
<< | przesunięcie bitowe w lewo |
>> | przesunięcie bitowe w prawo |
>>> | przesunięcie bitowe w prawo bez znaku |
Mały komentarz do każdego z nich i idziemy dalej.
KONIUNKCJA BITOWA
Iloczyn bitowy polega na zwróceniu liczby uzyskanej przez sumę potęg liczby 2, w których bit reprezentuje jedynkę. A jak to jest kalkulowane? Zapraszam do osobnego artykułu, lecz w dużym skrócie dochodzi do porównania każdego osobnego bitu dwóch podanych wartości jak pod kreską i czy w każdym bicie występuje jedynka. Jeżeli tak, to pod kreską ląduje wartość 1, w przeciwnym razie jest 0:
int a = 7 & 5;
Otrzymamy 5, ponieważ:
111
101
===
101
Środkowy bit wynosi zero, gdyż pięć w postaci binarnej nie posiada bitu równego jeden w tym samym miejscu. Po skonwertowaniu na system dziesiętny:
22 + 20 = 4 + 1 = 5
"That's all, folks!" 😊.
ALTERNATYWA BITOWA
Suma bitowa także zwraca sumę potęg liczby 2, jednak tutaj żeby w wyniku otrzymać bit równy jeden, wystarczy (jak przy alternatywie "zwykłej") żeby bit dowolnego składnika był jedynką:
int a = 7 | 5;
i w ten sposób otrzymamy siódemkę, bo:
111
101
===
111
W środkowym bicie uzyskujemy jedynkę, ponieważ znalazła się ona u samej góry. I to wystarczyło:
22 + 21 + 20 = 4 + 2 + 1 = 7
BITOWA ALTERNATYWA WYKLUCZAJĄCA
Mamy ten sam warunek, co przy alternatywie wykluczającej "zwykłej" co do ustalenia wartości każdego z bitów: nieparzysta liczba jedynek "rządzi"!
int i = 7 ^ 5;
Wynik równy dwa. Dlaczego? Ano dlatego:
111
101
===
010
Nieparzysta liczba jedynek jest tylko w przypadku bitu pośrodku. Stąd po zamianie na system dziesiętny:
21 = 2
co kończy dowód.
NEGACJA BITOWA
Negacja bitowa zamienia wartości wszystkich bitów na przeciwne:
int a = ~6;
O wiele ciekawiej prezentuje się rezultat poddany operacji na liczbie ujemnej:
int a = ~(-6);
Tu wynik będzie równy 5! Ktoś wie o co chodzi? Trzeba sięgnąć do architektury przechowywania liczb ujemnych w komputerze. Sam w sobie nie jest zdolny do takich rzeczy, dlatego z pomocą przychodzi kod uzupełnień do dwóch, nazywany krócej kodem U2. Rozpisując sobie wartości w bitach:
1010 (-6)
0101 (5)
Widać, że dla -6 pierwszy bit (najbardziej znaczący bit) jest ustawiony na jedynkę. To jest bit znaku, który oznacza w dużym skrócie ujemny składnik w sumie potęg dwójki występujących jako jedynka:
-6 = -(23) + 21 = -8 + 2
Kiedy zanegujemy bit znaku, przyjmuje wartość zero, zatem nie ma mowy o wartości ujemnej 🙂! To wszystko jest zaprezentowane łopatologicznie i najszybciej jak tylko można, więc zajrzyj proszę do osobnego artykułu, jeśli pragniesz więcej informacji.
PRZESUNIĘCIE BITOWE W LEWO
Przesunięcie bitowe w lewo określane jako "left bit shifting" oznacza mnożenie liczby przez 2 do potęgi N, gdzie to N wstawiacie po operatorze:
int a = 8 << 2;
8 mnożone przez 22 daje wynik nie inny jak 32.
PRZESUNIĘCIE BITOWE W PRAWO
Teraz "right bit shifing", czyli przesunięcie bitowe w prawo. To jest de facto operacja dzielenia całkowitoliczbowego przez 2 do potęgi N:
int a = 8 >> 2;
int b = -8 >> 2;
W obu przypadkach zostanie zwrócona liczba 2, tylko z innymi znakami, bo 8 dzielone na 22 daje wynik 2. Przestrzegam, że tu też narażamy się na obcinanie części dziesiętnej.
PRZESUNIĘCIE BITOWE W PRAWO BEZ ZNAKU
Ten rodzaj przesunięcia bitowego jest ekskluzywny dla języka Java, który wykonuje to samo, co "zwykłe" przesunięcie w prawo, z tym że nie uwzględnia bitu znaku, o którym była mowa wcześniej. Dlatego też dla przykładu:
-2 >>> 12
zwróci wynik 1,048,575 (220 - 1), ponieważ 32 potęga liczby 2 została "odsunięta" o 12 do tyłu:
10000000000000000000000000000010 (-2)
00000000000011111111111111111111 (1,048,575)
a 32 jest dlatego, bo w języku Java typ danych "int" reprezentuje maksymalny zakres równy 232 - 1. Dla liczby dodatniej działa tak samo, jak poprzednik.
PRZYPISANIA
I już ostatni rodzaj operatorów jakie są w języku Java i są to operatory przypisania. Znowu Cię pomęczę nową tabelką 😅:
OPERATOR | ZAPIS ALTERNATYWNY | ZNACZENIE |
= | brak | przypisanie |
+= | a = a + N | dodawanie do wartości |
-= | a = a - N | odejmowanie od wartości |
*= | a = a*N | mnożenie wartości |
/= | a = a / N | dzielenie wartości |
%= | a = a % N | przypisanie reszty z dzielenia |
&= | a = a & N | przypisanie wyniku iloczynu bitowego |
|= | a = a | N | przypisanie wyniku alternatywy bitowej |
^= | a = a ^ N | przypisanie wyniku bitowej alternatywy wykluczającej |
<<= | a = a << N | przypisanie wyniku przesunięcia bitowego w lewo |
>>= | a = a >> N | przypisanie wyniku przesunięcia bitowego w prawo |
>>>= | a = a >>> N | przypisanie wyniku przesunięcia bitowego w prawo bez znaku |
Pierwsza kolumna dotyczy skróconej formy zapisu, a druga oznacza to samo tylko pisane tradycyjnie. Na przykład dodawanie wartości do zmiennej może odbywać się tak:
a = a + 2; // dodanie wartości 2 do zmiennej "a"
albo tak:
a += 2; // dodanie wartości 2 do zmiennej "a"
Obie formy są równoważne. Ważne jest to, co pisałem wcześniej, nie myl operatora przypisania z operatorem porównania!
Operatory w języku Java dzielą się na arytmetyczne, relacyjne, logiczne, bitowe i przypisania.
To już wszystko co chciałem przekazać. Nawet nie próbuj się tego uczyć na pamięć. Najlepiej zrobić sobie kilkadziesiąt przykładów i zastosować te operatory w praktyce. Programowanie to nie sztuka zapamiętywania, to sztuka rozumienia 😊!
NASTĘPNY ARTYKUŁ: Komentarze w języku Java. Komentarz liniowy i blokowy