Operații pe tipuri primitive în Java. Învățarea Java

1. Operații aritmetice de bază

Următorul tabel listează operațiile aritmetice de bază utilizate în limbajul Java:

Să ne uităm la câteva reguli pentru lucrul cu operații aritmetice:

  • Expresiile sunt evaluate de la stânga la dreapta, cu excepția cazului în care sunt adăugate paranteze sau anumite operații au prioritate.
  • Operatorii *, / și % au prioritate mai mare decât + și -.

Exemplul 1: Operații aritmetice pe valori întregi

De exemplu, în acest cod, variabilele AȘi b va avea semnificații diferite:

Clasa publică BasicIntMath ( public static void main(String args) ( int a = 4 + 5 - 2 * 3; int b = 4 + (5 - 2) * 3; System.out.println("a = " + a) ; System.out.println("b = " + b) )

Rezultatul executiei:

A = 3 b = 13

  • Operația de scădere unară schimbă semnul singurului său operand.
  • Operatorul de adăugare unară returnează pur și simplu valoarea operandului său. În principiu, nu este necesar, dar este posibil.

Exemplul 2. Operații de adunare și scădere unare

clasă publică UnarySignOperation ( public static void main(String args) ( double a = -6; double b = +6; System.out.println(a); System.out.println(b); ) )
  • Când o operație de împărțire este efectuată pe un tip de date întreg, rezultatul acesteia nu va conține o componentă fracțională.

Exemplul 3: Împărțirea numerelor întregi

clasă publică IntDivision ( public static void main(String args) ( int a = 16 / 5; System.out.println(a); ) )

Rezultatul rulării acestui program:

  • Operanzii operațiilor aritmetice trebuie să fie de tip numeric. Operațiile aritmetice nu pot fi efectuate tipuri logice date, dar permis peste tipuri de date char deoarece în Java acest tip este în esență un fel de tip int.

Exemplul 4. Operații aritmetice pe variabile de tip char

clasă publică BasicCharMath1 ( public static void main(String args) ( char c = "n"; System.out.println(c); System.out.println(c + 1); System.out.println(c / 5) ;))

Rezultatul executiei:

N 111 22

Exemplul 5. Operații aritmetice pe variabile de tip char

clasă publică BasicCharMath2 ( public static void main(String args) ( char c1 = "1"; char c2 = "\u0031"; char c3 = 49; System.out.println(c1 + c2 + c3); ) )

Rezultatul executiei:

    Operatorul de divizare modulo este notat cu simbolul %. Acest operator returnează restul când primul număr este împărțit la al doilea. La împărțirea unui număr întreg, rezultatul va fi, de asemenea, un număr întreg.

Exemplul 6. Diviziunea modulului

clasă publică DivisionByModule ( public static void main(String args) ( int a = 6 % 5; double b = 6,2 % 5,0; System.out.println(a); System.out.println(b); ) )

Rezultatul executiei:

1 1.2000000000000002

2. Operații aritmetice compuse cu atribuire

Java are operatori speciali care combină operații aritmetice cu operatorul de atribuire. Luați în considerare următoarea expresie:

A = a + 4;

În Java, această operație poate fi scrisă după cum urmează:

A += 4;

Operatorii de atribuire compusă nu numai că reduc dimensiunea codului, dar vă permit și să efectuați conversii automate pe care operatorii obișnuiți nu le pot face.

Exemplul 5: Operații aritmetice compuse cu alocare

clasă publică CompoundOperations ( public static void main(String args) ( int a = 1; int b = 2; int c = 3; a += 3; b *= 2; c += a * b; System.out.println (a); System.out.println(b);
Studii pentru a deveni „Dezvoltator de jocuri” + angajare

Operatori în Java

Java folosește operatorii aritmetici uzuali + - * / pentru a reprezenta operațiile de adunare, scădere, înmulțire și împărțire.

Operatorul / denotă diviziunea întregului dacă ambele argumente sunt numere întregi. În caz contrar, acest operator indică împărțirea numerelor în virgulă mobilă. Restul unei diviziuni întregi (adică, funcția mod) este notat cu simbolul %.
De exemplu, 15/2 este egal cu 7, 15%2 este egal cu 1 și 15 este . 0/2 este egal cu 7. 5.

Rețineți că o împărțire a întregului cu 0 ridică o excepție, în timp ce o împărțire în virgulă mobilă cu 0 are ca rezultat infinit sau NaN.

Operatori aritmetici poate fi folosit pentru a inițializa variabile.

int n = 5;
int a = 2 *n; // Valoarea variabilei a este 10.

Este convenabil să utilizați operatori aritmetici binari prescurtați în operatorii de atribuire.

De exemplu, operatorul
x + = 4;
este echivalent cu operatorul
x = x + 4;

(Operatorii de atribuire scurtă sunt formați prin prescrierea unui simbol de operator aritmetic, cum ar fi * sau %, înaintea simbolului =, cum ar fi *= sau %=.)

Unul dintre obiectivele declarate ale limbajului Java este independența mașinii.

Calculele trebuie să producă același rezultat, indiferent de mașina virtuală care le realizează. Pentru calcule aritmetice peste numere în virgulă mobilă, aceasta sa dovedit brusc a fi o sarcină dificilă. Tipul dublu folosește 64 de biți pentru a stoca valori numerice, dar unele procesoare folosesc registre în virgulă mobilă de 80 de biți. Aceste registre oferă o precizie suplimentară în timpul etapelor intermediare ale calculului Luați în considerare următoarea expresie ca exemplu:

dublu w = x * y / z;

Multe procesoare Intel evaluează expresia x * y și stochează acest rezultat intermediar într-un registru de 80 de biți, apoi îl împart la valoarea variabilei z și în final rotunjește răspunsul la 64 de biți. În acest fel, puteți crește acuratețea calculelor evitând depășirea. Cu toate acestea, acest rezultat poate fi diferit dacă toate calculele sunt efectuate pe un procesor pe 64 de biți.

Din acest motiv, în descrierea originală mașină virtuală Java a specificat că toate calculele intermediare ar trebui să fie rotunjite. Acest lucru a indignat comunitatea informatică. Nu doar calculele rotunjite pot provoca debordare. Ele sunt de fapt mai lente decât calculele mai precise, deoarece operațiunile de rotunjire durează anumit timp. Drept urmare, dezvoltatorii de limbaj Java s-au răzgândit, căutând să rezolve conflictul dintre performanța optimă și reproductibilitatea excelentă.

În mod implicit, dezvoltatorii de mașini virtuale permit acum utilizarea preciziei extinse în calculele intermediare. Cu toate acestea, metodele marcate cu cuvântul cheie strictfp trebuie să utilizeze operații precise în virgulă mobilă pentru a asigura rezultate reproductibile. De exemplu, metoda principală poate fi marcată cu cuvinte cheie, după cum se arată mai jos:
public static strictfp void main (Argumente șir)

În acest caz, toate comenzile din cadrul metodei principale vor efectua operații exacte asupra numerelor în virgulă mobilă.

Detaliile acestor operațiuni sunt strâns legate de caracteristicile de operare ale procesoarelor Intel. În mod implicit, rezultatele intermediare pot folosi exponentul extins, dar nu mantisa extinsă. (Cipurile Intel acceptă rotunjirea mantisei fără a sacrifica performanța.) Prin urmare, singura diferență între calculele implicite și calculele exacte este că calculele exacte pot cauza depășire, în timp ce calculele implicite nu.

Dacă ochii îți strălucesc în timp ce citești acest comentariu, nu-ți face griji. Pentru majoritatea programatorilor, această problemă este complet neimportantă. În majoritatea cazurilor, depășirea nu are loc în calculele cu virgulă mobilă. În această carte nu vom folosi cuvânt cheie strictfp.

Operatori de creștere și decrementare

Programatorii, desigur, știu că una dintre cele mai comune operații cu variabile numerice este adunarea sau scăderea uneia. În limbajul Java, ca și în limbajele C și C++, există operatori de incrementare și decrementare: operatorul x++ adaugă unul la valoarea curentă a variabilei x, iar operatorul x- scade unul din aceasta.

De exemplu, cod
int n = 12;
n++;
face valoarea variabilei n egală cu 13.

Deoarece acești operatori modifică valoarea unei variabile, ei nu pot fi aplicați numerelor în sine. De exemplu, operatorul 4++ este invalid.

Există două tipuri de acești operatori. Mai sus este prezentată forma „postfix” a operatorului, în care simbolurile operației sunt plasate după operand. Există, de asemenea, o formă „prefix” - ++n.
Ambii acești operatori măresc valoarea unei variabile cu unul. Diferența dintre ele apare doar atunci când acești operatori sunt utilizați în expresii. Forma de prefix a operatorului de increment adaugă mai întâi unul la valoarea variabilei, în timp ce forma de postfix folosește valoarea veche a acelei variabile.

int m = 7;
int n = 7;
int a = 2 * ++m; // Acum valoarea lui a este 16, iar m este 8.
int b = 2 * n++; // Acum valoarea lui b este 14, iar n este 8.

(Deoarece operatorul ++ a fost cel care a dat numele lui C++, acesta a fost motivul primei glume despre el. Detractorii subliniază că până și numele acestui limbaj conține o eroare: „În plus, acest limbaj ar trebui să se numească ++C , deoarece dorim să folosim acest limbaj numai după ce a fost îmbunătățit.")

În ordinea priorității, operatorii unari sunt urmați de operatori aritmetici. Acest grup include cei mai comuni patru operatori: adunare, scădere, înmulțire, împărțire. Și nu numai ei. Există, de asemenea, un operator de diviziune modulo, care este notat cu semnul %. Operatorii aritmetici sunt împărțiți în două grupuri. Primul grup cu prioritate mai mare conține *, /, %. În al doilea, respectiv, + și -.

Înmulțirea și împărțirea (* și /)

Operatorii * și / efectuează înmulțirea și împărțirea pe toate primitivele tipuri numericeși char. Când se împarte la zero, se întâmplă ArithmeticException.

Probabil vă întrebați de ce vă vorbesc despre înmulțire și împărțire, pe care le cunoașteți încă din clasa întâi. Cu toate acestea, în programare ne ocupăm de unele limitări asociate cu reprezentarea numerelor într-un computer. Aceste restricții se aplică tuturor formatelor de numere, de la octet la dublu. Dar ele sunt cele mai vizibile pentru tipul întreg int .

Dacă înmulțiți sau împărțiți două numere, rezultatul este calculat folosind aritmetica întregului și stocat fie într-un int sau long . Dacă numerele sunt foarte mari, atunci rezultatul va fi mai mare decât numărul maxim care poate fi reprezentat în acele numere. Aceasta înseamnă că rezultatul nu va putea fi codificat corect de computer și nu va avea nicio semnificație. De exemplu, tipul octet este folosit pentru a reprezenta numere în intervalul de la -128 la 127. Dacă înmulțim 64 și 4, rezultatul este 256, care are notație binară 100000000 nouă caractere vor fi codificate ca 0, deoarece byte folosește doar 8 caractere.

Să ne uităm la împărțire. Dacă împărțiți în aritmetică întregi, rezultatul trebuie să fie un întreg. Aceasta înseamnă că partea fracțională se va pierde. De exemplu, 7/4 ne dă 1,75, dar în aritmetica întregului ar fi 1.

În acest fel, dacă ai de-a face cu expresii complexe, poți alege succesiunea înmulțirilor și împărțirilor. Dar rețineți că înmulțirea poate duce la revărsare, iar diviziunea - la pierderea preciziei. Înțelepciunea populară susține că efectuarea mai întâi înmulțiri și apoi împărțiri va produce în cele mai multe cazuri rezultatul corect. Să ne uităm la un exemplu:

1. int a = 12345, b = 234567, c, d;
2. lung e, f;
3.
4. c = a * b / b; // trebuie să fie egal cu a=12345
5. d = a / b * b; // ar trebui să fie, de asemenea, egal cu a=12345
6. System.out.println(„a este „ + a +
7. „\nb este „ + b +
8. „\nc este „ + c +
9. „\nd este „ + d);
10.
11. e = (lung)a * b / b;
12. f = (lung)a / b * b;
13. System.out.println(
14. „\ne este „ + e +
15. „\nf este „ + f);

Rezultatul acestui fragment va produce următoarele:

A este 12345
b este 234567
c este -5965
d este 0
e este 12345
f este 0

Nu-i lăsa să te deranjeze valori numerice acest exemplu. Important este că atunci când am făcut mai întâi înmulțirea, am primit un overflow (c este -5965 ) când l-am codificat în tip int. Cu toate acestea, putem obține rezultatul corect dacă îl codificăm într-un tip mai lung, cum ar fi long . În ambele cazuri, aplicarea diviziunii mai întâi va fi dezastruoasă pentru rezultat, indiferent de lungimea tipului acesteia.

Diviziune modul %

Rezultatul diviziunii modulo este restul diviziunii. De exemplu, 7/4 este 1 cu un rest de 3. Prin urmare, 7%4 = 3. De obicei operanzii au tip întreg, dar uneori operatorul este aplicat numerelor în virgulă mobilă. Ar trebui să cunoașteți și câteva caracteristici al acestui operator, când operanzii sunt negativi.

Pentru operanzi negativi sau fracționari, regula este: scădeți operandul drept din cel stâng până când acesta din urmă este mai mic decât primul. Exemple:

17%5 = ? 17-5=12>5; 12-5=7>5; 7-5=2<5. Значит 17%5 = 2

21%7? 21-7=14>7; 14-7=7=7; 7-7=0<7. Значит 21%7 = 0

7.6%2.9? 7.6-2.9=4.7>2.9; 4.7-2.9=1.8<2.9. Значит 7.6%2.9=1.8

Notă: semnul rezultatului (pozitiv sau negativ) este determinat în întregime de semnul operandului din stânga, adică dividendul.

Când împărțirea modulo este efectuată pe numere fracționale, esența acestei operații este de a scădea divizorul de mai multe ori. Rezultatul poate fi și un număr fracționar.

O regulă simplă pentru operanzii negativi este aceasta: aruncați semnul minus din operanzi, faceți împărțirea modulo cu operanzii pozitivi și apoi prefixați rezultatul cu semnul minus dacă operandul din stânga (dividendul) a fost negativ.

Diviziunea Modulo, ca și diviziunea normală, poate arunca o ArithmeticException dacă divizorul (operandul din dreapta) este egal cu zero.

Ultima actualizare: 30.10.2018

Majoritatea operațiunilor din Java sunt similare cu cele utilizate în alte limbaje asemănătoare C. Există operații unare (efectuate pe un operand), operații binare pe doi operanzi și operații ternare pe trei operanzi. Un operand este o variabilă sau o valoare (cum ar fi un număr) implicată într-o operație. Să luăm în considerare toate tipurile de operațiuni.

Operațiile aritmetice implică numere. Java are operații aritmetice binare (efectuate pe doi operanzi) și operații aritmetice unare (efectuate pe un operand). Operațiile binare includ următoarele:

    operația de adunare a două numere:

    Int a = 10; int b = 7; int c = a + b; // 17 int d = 4 + b; // unsprezece

    operația de scădere a două numere:

    Int a = 10; int b = 7; int c = a - b; // 3 int d = 4 - a; // -6

    operația de înmulțire a două numere

    Int a = 10; int b = 7; int c = a * b; // 70 int d = b * 5; // 35

    operația de împărțire a două numere:

    Int a = 20; int b = 5; int c = a / b; // 4 dublu d = 22,5 / 4,5; // 5.0

    Un lucru de reținut atunci când împărțiți este că, dacă operația implică două numere întregi, rezultatul împărțirii va fi rotunjit la cel mai apropiat număr întreg, chiar dacă rezultatul este atribuit unei variabile flotante sau duble:

    Dublu k = 10 / 4; // 2 System.out.println(k);

    Pentru ca rezultatul să reprezinte un număr în virgulă mobilă, unul dintre operanzi trebuie să reprezinte și un număr în virgulă mobilă:

    k dublu = 10,0 / 4; // 2.5 System.out.println(k);

    obținerea restului la împărțirea a două numere:

    Int a = 33; int b = 5; int c = a % b; // 3 int d = 22% 4; // 2 (22 - 4*5 = 2)

Există, de asemenea, două operații aritmetice unare care sunt efectuate pe un singur număr: ++ (incrementare) și -- (decrementare). Fiecare dintre operații are două soiuri: prefix și postfix:

    ++ (increment de prefix)

    Implică creșterea unei variabile cu una, de exemplu z=++y (mai întâi valoarea variabilei y este mărită cu 1, iar apoi valoarea acesteia este atribuită variabilei z)

    Int a = 8; int b = ++a; System.out.println(a); // 9 System.out.println(b); // 9

    ++ (increment postfix)

    De asemenea, reprezintă o creștere a unei variabile cu unul, de exemplu z=y++ (mai întâi valoarea variabilei y este atribuită variabilei z, iar apoi valoarea variabilei y este mărită cu 1)

    Int a = 8; int b = a++; System.out.println(a); // 9 System.out.println(b); // 8

    -- (prefix scadere)

    scăderea unei variabile cu unu, de exemplu, z=--y (mai întâi valoarea variabilei y este redusă cu 1, apoi valoarea acesteia este atribuită variabilei z)

    Int a = 8; int b = --a; System.out.println(a); // 7 System.out.println(b); // 7

    -- (scădere postfix)

    z=y-- (mai întâi valoarea variabilei y este atribuită variabilei z, iar apoi valoarea variabilei y este decrementată cu 1)

    Int a = 8; int b = a--; System.out.println(a); // 7 System.out.println(b); // 8

Prioritatea operațiilor aritmetice

Unele operații au prioritate mai mare decât altele și, prin urmare, sunt efectuate mai întâi. Operațiuni în ordinea descrescătoare a priorității:

++ (creștere), -- (scădere)

* (înmulțire), / (diviziune), % (diviziune rest)

+ (adunare), - (scădere)

Precedența operațiilor trebuie luată în considerare la executarea unui set de expresii aritmetice:

Int a = 8; int b = 7; int c = a + 5 * ++b; System.out.println(c); // 48

Operația de incrementare ++b va fi executată prima, care are prioritate mai mare - va incrementa valoarea variabilei b și o va returna ca rezultat. Apoi se realizează înmulțirea 5 * ++b și doar în sfârșit se realizează adunarea a + 5 * ++b

Parantezele vă permit să redefiniți ordinea calculelor:

Int a = 8; int b = 7; int c = (a + 5) * ++b; System.out.println(c); // 104

Chiar dacă operația de adunare are o prioritate mai mică, adunarea va fi efectuată mai întâi, nu înmulțirea, deoarece operația de adunare este inclusă în paranteze.

Asociativitatea operațiilor

Pe lângă prioritate, operațiunile diferă într-un astfel de concept ca asociativitatea. Când operațiunile au aceeași prioritate, ordinea evaluării este determinată de asociativitatea operatorilor. În funcție de asociativitate, există două tipuri de operatori:

    Operatori asociativi stânga, care sunt executați de la stânga la dreapta

    Operatori asociativi dreapta, care sunt executați de la dreapta la stânga

Astfel, unele operații, precum înmulțirea și împărțirea, au aceeași prioritate. Care va fi atunci rezultatul în expresia:

Int x = 10 / 5 * 2;

Ar trebui să interpretăm această expresie ca (10 / 5) * 2 sau ca 10 / (5 * 2)? La urma urmei, în funcție de interpretare, vom obține rezultate diferite.

Deoarece toți operatorii aritmetici (cu excepția prefixului increment și decrement) sunt asociativi la stânga, adică sunt executați de la stânga la dreapta. Prin urmare, expresia 10 / 5 * 2 trebuie interpretată ca (10 / 5) * 2, adică rezultatul va fi 4.

Operații cu virgulă mobilă

Trebuie remarcat faptul că numerele cu virgulă mobilă nu sunt potrivite pentru calcule financiare și alte calcule în care erorile de rotunjire pot fi critice. De exemplu:

Dublu d = 2,0 - 1,1; System.out.println(d);

În acest caz, variabila d nu va fi egală cu 0,9, așa cum s-ar putea presupune inițial, ci 0,899999999999999. Aceste erori de precizie apar deoarece la un nivel scăzut, sistemul binar este folosit pentru a reprezenta numere în virgulă mobilă, dar nu există o reprezentare binară pentru numărul 0,1 și nici pentru alte valori fracționale. Prin urmare, în astfel de cazuri, se utilizează de obicei clasa BigDecimal, care vă permite să ocoliți astfel de situații.