miercuri, 18 septembrie 2019

Prelucrarea tablourilor unidimensionale în Java


Un vector, tablou, masiv unidimensional sau array reprezintă un container pentru un număr de elemente de același tip, fiecare element fiind indexat de un număr. 
În limbajul Java vectorii sunt obiecte, tipul acestora fiind referință.

Vectorii sunt de 2 tipuri:
1.  cu lungime fixă – dimensiunea  vectorului este stabilită la crearea acestuia și nu poate fi modificată ulterior. Pentru ei nu există o clasă care se instanţiază  pentru a obține un obiect vector.
2. cu lungime variabilă – dimensiunea vectorului poate fi modificată pe parcursul rulării programului. Pentru ei există clase Java predefinite ce pot fi instanțiate (de ex.  java.util.Vector, java.util.Arrays, ș.a).

Fiecărui element dintr-un vector îi corespunde un index numeric, cu ajutorul căruia poate fi accesat. Numerotarea elementelor începe întotdeauna de la 0, ceea ce înseamnă că, de exemplu, cel de-al nouălea element va fi accesat de indexul 8.

Pentru a folosi un vector este necesar să:

1. declarați o variabilă de tip vector care va servi drept referință către vectorul propriu-zis: 
Pentru a declara o variabila de tip vector se va respecta sintaxa:
tip [] nume;
unde
tip este tipul de date al elementelor conținute de vector;
[ ] sunt simboluri speciale ce indică ca variabila respectivă este un vector;
nume este identificatorul variabilei vectorului;

Ca şi în cazul altor tipuri de variabile, declararea nu creează de fapt un vector, dar pur şi simplu anunță compilatorul că variabila respectivă va deține un vector de tipul specificat. Deci, la această etapă vectorul nu poate fi utilizat.
Exemple:
byte[]unVectorDeTipByte;
short[]unVectorDeTipShort;
double[]unVectorDeTipDouble;
boolean[]unVectorDeTipBoolean;
char[]unVectorDeTipChar;
String[]unVectorDeTipString;
 

2. creați vectorul și stabiliți dimensiunea acestuia, adică numărul de elemente pe care le va putea conține.
Un vector poate fi creat utilizând operatorul new printr-o construcție de forma: 
new tip_vector [dimensiune]; 
unde:
tip_vector reprezintă tipul elementelor stocate în vector
dimensiune este o expresie de tip întreg pozitivă ce semnifică numărul de elemente ce se vor stoca în vector.

Întreaga construcție va crea un vector de tip tip_vector cu o dimensiune de dimensiune elemente indexate de la 0 la dimensiune-1.

Dacă această instrucțiune ar lipsi, compilatorul ar afișa o eroare asemănătoare celei de mai jos și execuția programului ar eșua:    
Variable anArray may not have been initialized.
De exemplu:
int [] a; // se declară variabila a ce conţine referință către un vector cu elemente întregi
a = new int[5];     // se crează un vector cu 5 elemente întregi de același tip cu variabila a  

3. accesați elementele vectorului, folosind variabila declarată, fie pentru a le atribui valori, fie pentru a citi valorile deja stocate.
Fiecare element distinct din vector poate fi accesat ca o variabilă separată printr-o construcție de forma:
nume [index]
unde 
nume reprezintă numele vectorului ce stochează elementele
index este o expresie de tip întreg strict pozitivă ce semnifică poziția elementului care doriți să îl accesați din vectorul dat. 

Dacă vectorul conține elemente atunci index trebuie să fie cuprins în intervalul  [0, n-1], în caz contrar o excepție de execuție va fi semnalată.

De exemplu:
int [] a; // se declară variabila a ce conţine referință către un vector cu elemente întregi
a = new int[5]; // se crează un vector cu 5 elemente întregi de același tip cu variabila a
a[0] = 23;    // primului element din vector i se atribuie valoarea 23
a[4] = 10;    // ultimului element din vector i se atribuie valoarea 10
a[5] = 9;     // excepție generată! Indexul nu se află în diapazonul [0,4]

Exemplu A: Declararea, inițializarea și afișarea pe ecran a elementelor unui vector

class ExArray {
  public static void main(String[] args) {
   int[] anArray;
   anArray = new int[10];
       
   anArray[0] = 100;
   anArray[1] = 200;
   anArray[2] = 300;
   anArray[3] = 400;
   anArray[4] = 500;
   anArray[5] = 600;
   anArray[6] = 700;
   anArray[7] = 800;
   anArray[8] = 900;
   anArray[9] = 1000;
        
System.out.println("Elementul cu index 0: " + anArray[0]);
System.out.println("Elementul cu index 1: " + anArray[1]);
System.out.println("Elementul cu index 2: " + anArray[2]);
System.out.println("Elementul cu index 3: " + anArray[3]);
System.out.println("Elementul cu index 4: " + anArray[4]);
System.out.println("Elementul cu index 5: " + anArray[5]);
System.out.println("Elementul cu index 6: " + anArray[6]);
System.out.println("Elementul cu index 7: " + anArray[7]);
System.out.println("Elementul cu index 8: " + anArray[8]);
System.out.println("Elementul cu index 9: " + anArray[9]);
}}


Alternativ, poate fi creat și inițializat un vector în felul următor:

int[] anArray = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};

În acest caz, dimensiunea vectorului este determinată automat de numărul de valori specificate între acolade și poate fi obținută prin anArray.length.

Deci, fiecare vector conține, pe lângă elemente, o variabilă de instanță publică ce nu poate fi modificată numită length ce stochează numărul de elemente în vector. 

Prin urmare accesând această variabilă putem obține lungimea unui vector.

Exemplu:
double[] v;
v = new double[5];
System.out.println(v.length);      // se va afișa valoarea 5

Expresia:
double[] v;
v = new double[5];

este echivalentă cu expresia:
 double[] v = new double[5];

Orice vector îndată ce a fost declarat este inițializat cu valori default după cum urmează: 
  • pentru byte, shortintlong - valoarea default este 0;
  • pentru float, double - valoarea default este 0.0;
  • pentru boolean - valoarea default este false;
  • pentru obiecte - valoarea default este null;
Exemplul B Inițializarea unui vector cu valori implicite (default):

public class Main {
public static void main(String[] args) {
int[] v = new int[5]; 

System.out.println("Valorile implicite ale vectorului sunt:");
for (int i = 0; i < v.length; i++) {
 System.out.println("v[" + i + "] = " + v[i]);
}}}

Exemplul D Citirea valorilor unui vector de la tastatură

import java.util.Scanner;
public class Main {
 public static void main(String[] args) {
  Scanner sc = new Scanner(System.in);
   int[] v = new int[5]; // vector cu 5 elemente
   for (int i = 0; i < v.length; i++) {
   System.out.print("Introduceți elementul " + i + ": ");
   v[i] = sc.nextInt();
}
System.out.println("Vectorul introdus este:");
for (int x : v) {
   System.out.print(x + " ");
}}}

Rețineți! 
for (int x : v) {
   System.out.print(x + " ");
}
Acestei forme a instrucțiunii for i se mai spune în Java for-each sau forma scurtă a ciclului for. Dacă ar fi să traducem această instrucțiune în limba română ar suna cam în felul următor: pentru fiecare element x din vectorul v afișează la ecran pe x
Această formă a instrucțiunii parcurge automat toate elementele vectorului v și la fiecare iterație, variabila x primește valoarea curentă din vector. Aici nu există de a depăși limitele vectorului, pentru că nu se lucrează cu i. Este ideal pentru citirea elementelor, afișări, calcule simple. Pe lângă aceste beneficii, sunt desigur și limitări. Nu poți modifica valorile direct în vector prin variabila x, deoarece x este doar o copie a elementului. Nu ai acces la index, deci nu-l poți folosi când ai nevoie să știi poziția unui element.

Exemplul D găsirea elementului minim dintr-un vector folosind for-each

public class Main {
    public static void main(String[] args) {
        int[] v = {12, -3, 45, 0, 7, -10, 9};

        int minim = v[0]; 

        for (int x : v) {
            if (x < minim) {
                minim = x;
            }}

        System.out.println("Elementul minim este: " + minim);
    }
}


Să identificăm, din cele expuse mai sus, care sunt restricțiile impuse în lucrul cu masivele unidimensionale în Java: 
  • Dimensiunea tabloului este fixă, deci ea NU poate fi modificată.
  • Pentru a declara un vector se folosește sintaxa: tip[] denumire = new tip[dimensiune];
  • Tipul vectorului poate fi atât primitiv, cât și referință.
  • Vectorul o dată ce a fost declarat este inițializat cu valori default.
  • Indexarea elementelor în vector începe de la 0.
  • Accesul în afara limitelor indicilor elementeor produce eroare de execuție: ArrayIndexOutOfBoundsException.




miercuri, 20 februarie 2019

Cum creem fișiere executabile în Java?


Utilitarul jar (Java Archive) care face parte din pachetul JDK oferă oportunitatea de a crea arhive jar executabile. O astfel de arhivă invocă metoda main a unei clase la efectuarea unui click dublu pe aceasta. 

Pentru a crea un fișier java executabil, este necesar crearea fișierului manifest ce are extensia .mf

Ps! Mai întâi și întâi trebuie, desigur, să aveți finisat codul aplicației sau proiectului. Eu am creat anterior un mini Notepad.

Pentru a crea fișierul manifest utilizați aplicația Notepad sau Wordpad și respectați sintaxa conținutului acestuia:

Main-Class: First 

First este numele clasei principale. De exemplu:

Main-Class: Notepad 

În fișierul .mf după numele clasei se va însera obligatoriu un rând liber. Salvați fișierul cu extensia .mf.

Folosind aplicația CMD, compilați aplicația Java:

Creați arhiva respecând sintaxa:

jar -cvmf myfile.mf myjar.jar First.class 

myfile.mf - numele fișierului manifest 

myjar.jar – numele viitoarei arhive jar 

First.class - numele fișierului binar creat de către JVM în urma compilării reușite a aplicației Java. 
Deci, conform exemplului meu:

În rezultat, în dosarul cu fișierele de lucru a fost creată arhiva executabila Java, Notepad.jar:



După executarea a dublu click pe acestă arhivă se va invoca metoda main() a aplicației:





Sper că această postare vă este utilă.

Este binevenit orice comentariu!

Să aveți parte de o zi extraordinară !!!!!

joi, 7 februarie 2019

Clasele ce descriu excepții în Java

În această postare vom explora un aspect crucial al programării în limbajul Java, și anume gestionarea excepțiilor. 

Programarea este adesea o călătorie plină de provocări, iar uneori codul nostru întâmpină situații neașteptate. Cum reacționăm în fața acestor situații este esențial pentru a construi aplicații fiabile.

Procesul de programare este mereu însoțit de diverse probleme legate de viitorul soft. Programatorului îi revine misiunea de a prezice care sunt aceste probleme ce pot apărea în procesul execuției software-ului și de a reduce la minim apariția acestora.

Din punct de vedere al programării, excepțiile reprezintă situații excepționale care pot apărea în timpul execuției programelor noastre și duc la oprirea acestuia. Acestea pot fi cauzate de diverse evenimente, cum ar fi introducerea incorectă a datelor, împărțire la 0, accesarea unui fișier care nu există, accesarea indexului unui tablou care depășește limitele acestuia, omiterea programării metodei main(), accesarea unui obiect căruia nu i s-a oferit spațiu de memorie, probleme de conexiune la rețea/bază de date sau chiar erori logice în cod. Ignorarea acestor excepții ar putea duce la comportamente imprevizibile ale aplicațiilor noastre, până la blocarea completă a acestora.

Procesul de izolare a situațiilor excepționale și controlul comportării aplicației în momentul apariției acestora este numit tratarea sau gestionarea excepțiilor
Cu alte cuvinte, gestionarea excepțiilor se referă la anticiparea și tratarea cu atenție a acestor situații neașteptate.

Limbajul de programare Java, are instrumente puternice, cum ar fi blocurile try-catch și clauza throws, care ne permit să detectăm, să gestionăm și să raportăm erorile într-un mod controlat.

Java pune la dispoziția programatorilor clasa Throwable din care sunt extinse toate clasele de excepții, şi care face parte din următoarea ierarhie:



Clasa Throwable împarte excepțiile în două categorii:

1. Excepții de compilare (verificate, checked, Compile-Time Exceptions). Sunt excepții verificate la faza de compilare. Nu țin de algoritm, ci de anumite condiții care ar putea afecta execuția programului (ex. fișier absent, date de intrare nevalide, probleme ce țin de baze de date, ș.a). Dacă un oarecare cod dintr-o metodă ar putea genera o astfel de excepție atunci este obligatoriu de a oferi un mecanism de tratate a acesteia fie prin try...catch fie cu ajutorul cuvântul rezervat throws, în caz contrar aplicația nu va putea fi lansată la execuție. Programatorul este forțat să trateze așa tip de excepții.

Exemple de excepții verificate:
IOException -  Generată pentru erori de intrare/ieșire, cum ar fi citirea sau scrierea într-un fișier.
FileNotFoundException - Generată de tentativa de a accesa un fișier absent.
SQLException - Generată pentru erori legate de accesul la baze de date.
ClassNotFoundException - Generată atunci când o clasă specificată nu este găsită în timpul încărcării.

2. Excepții de execuție (neverificate, unchecked, Runtime Exceptions). Sunt excepții generate la faza de execuție a programului, și sunt o consecință a neatenției programatorului la elaborarea algoritmului. Acestea de asemenea pot fi tratate, însă la discreția programatorului.

Exemple de excepții neverificate:
ArithmeticException - Generată pentru erori aritmetice, cum ar fi împărțirea la zero.
NullPointerException - Generată atunci când se încearcă să se acceseze un obiect sau un câmp al unui obiect care este null.
ArrayIndexOutOfBoundsException - Generată atunci când se încearcă accesarea unui index în afara limitelor unui tablou.
NumberFormatException - Conversia dintr-un șir de caractere într-un număr a eșuat.

Instanțele clasei Error reprezintă erori interne, nerecuperabile, ale mediului de lucru Java. Sunt rezervate pentru situații în care este dificil sau imposibil să se recupereze și să se continue execuția programului. Acestea nu ar trebui să fie gestionate printr-un bloc try-catch, deoarece încercarea de a le gestiona ar putea agrava problema sau ar putea duce la comportamente neașteptate.
Este important să subliniem că, în general, gestionarea excepțiilor de tip Error nu este recomandată, deoarece acestea indică condiții de execuție foarte grave și, de cele mai multe ori, nu există o modalitate practică de recuperare. Programatorii ar trebui să se concentreze pe prevenirea acestor situații prin proiectare și testare adecvată a codului.

Exemple de excepții de tip Error:
OutOfMemoryError - Generată atunci când sistemul nu mai are suficientă memorie pentru a continua execuția programului. De obicei, nu este gestionată, deoarece recuperarea dintr-o eroare de lipsă de memorie este problematică.
LinkageError - Generată atunci când o problemă apare în legătură cu încărcarea sau legarea dinamică a claselor și a resurselor la timpul de rulare. De obicei, indică o problemă semnificativă în structura sau configurarea programului.

Pentru a înțelege mai bine ce este excepția analizați exemplul următor în care cerem utilizatorului să introducă două numere întregi de la tastatură și vom afișa împărțirea întreagă a acestora:
import java.util.*;
class Exceptie_impartire{
public static void main(String[] args) {
Scanner citire = new Scanner(System.in);
System.out.println("Introduceți doua numere: ");
int numar1 = citire.nextInt();
int numar2 = citire.nextInt();
System.out.println(numar1+"/"+numar2+" = "+(numar1 / numar2));
citire.close();
}}
Dacă veți introduce de la tastatură pentru al doilea număr valoarea 0, programul va genera o eroare de rulare, excepție de tip ArithmeticException, deoarece nu puteți împărți un număr întreg la 0.

 


Numerele în virgulă mobilă împărțite la 0 nu vor genera excepție.

O modalitate simplă de a remedia această eroare este să adăugați o declarație if pentru a testa al doilea număr, ca de exemplu:
import java.util.*;
class Exceptie_impartire_if {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Scanner citire = new Scanner(System.in);
System.out.println("Introduceti doua numere: ");
int numar1 = citire.nextInt();
int numar2 = citire.nextInt();
if(numar2 != 0)
System.out.println(numar1+"/"+numar2+" = "+(numar1/numar2));
else
System.out.println("Nu puteti / 0 un numar intreg! ");
}}
Java, la fel ca alte limbaje de programare, oferă tehnici speciale ce permit interceptarea și tratarea excepțiilor într-un mod standard și destul de comod.

În Java tratarea excepțiilor este obligatorie, orice secvență de cod ce poate provoca excepții trebuie să fie însoțită şi de o modalitate de tratare a acesteia:

1) declararea excepției în semnătură metodei:

De exemplu:
public static void main(String  [] args)
throws FileNotFoundException {
// corpul metodei ce conține codul ce poate genera excepții
}

2) folosind blocurile try ... catch...finally:

Blocul try blochează toate instrucțiunile ce pot genera excepții. Are sintaxa:
try{
// instrucțiuni ce pot genera excepții
}
Rețineți!
👉 Un bloc try poate fi urmat fie de un bloc catch fie de un bloc finally, însă nu poate exista de unul singur.
👉 Dacă instrucțiunile grupate de blocul try vor genera o excepție aceasta va fi tratată de blocul catch corespunzător tipului de eroare aruncată (generată).
👉 Dacă instrucțiunile se vor executa cu succes nu se va mai ține cont de tratarea excepțiilor și aplicația se va executa în mod normal.

Blocul catch este blocul în care sunt tratate excepțiile. Are sintaxa:
catch (ClasaDeExceptii numeVariabila{
/ / instrucţiuni de tratare
}
ClasaDeExceptii reprezintă clasa excepției tratate. 
numeVariabila este o variabilă cu ajutorul căreia putem accesa metodele clasei excepției tratate. Deseori cu această variabilă nu se lucrează dar şi în acest caz ea trebuie declarată obligatoriu altfel obținem eroare sintactică precum că nu s-a respectat sintaxa instrucțiunii catch.

Rețineți!
👉 Blocul catch NU poate exista singur, ci doar însoțit de un bloc try: try {...} catch(...) {}
👉 Între blocul try şi primul bloc catch nu pot exista alte instrucțiuni.
👉 Un bloc try poate fi însoțit de orice număr de blocuri catch.

Exemplu de generare fără gestionare a excepției ArrayIndexOutOfBoundException:
public class ExceptieExemplu {
public static void main (String [] args){
int [] s={1,2,3,4};
System.out.println(s[6]);
System.out.println(s[0]);
System.out.println("Alte instructiuni");
}}

Exemplu de generare cu gestionare a excepției ArrayIndexOutOfBoundException:

public class ExceptieExemplu {
    public static void main (String [] args){
int [] s={1,2,3,4};
try {
System.out.println(s[6]);
}catch (IndexOutOfBoundsException ex){
System.out.println("Nu avem asa indice pentru tablou!");
}
System.out.println("Alte instructiuni");
System.out.println(s[0]);}
}
Blocul finally nu apare niciodată singur ci în asociere cu blocul try. Cuprinde codul care trebuie să se execute indiferent dacă apar excepții în blocul try sau nu. Prin clauza finally instrucțiunea try...catch devine completă. Acest bloc are sintaxa:
finally {
// instrucțiuni executate indiferent
}
Instrucțiunea try...catch...finally are următoarea formă completă :

Să înțelegem acest mecanism prin analizarea unui exemplu comparativ: 


Exemplu de gestionare a excepțiilor de tip împărțire la 0 și depășire de index:
class exe6 {
public static void main(String [] args){
int x= (int)(Math.random()*5);
int y= (int)(Math.random()*8);
int [] z={1,2,3,4,5};
try {
System.out.println("Sau generat numerel: "+x+" "+y);
System.out.println("x/y este "+x/y);
System.out.println("y="+y+"z[y]="+z[y]);
}catch (ArithmeticException e1 ){
System.out.println("problema aritmetica : Impartire la 0");
}catch (IndexOutOfBoundsException e2){
System.out.println("depasire de index"+e2);
}finally {
System.out.println("Elaborat de mine !");
}}}




Pe lângă faptul că limbajul Java oferă mecanisme pentru gestionarea excepțiilor standarde, programatorul are posibilitatea de a crearea și tratarea excepții personalizate. 
De obicei de acest lucru este nevoie atunci când apare o situație în care oricare excepție predefinită Java nu este relevantă. 

Pentru aceasta programatorul are la dispoziție instrucțiunea throw, care poate fi folosită în felul următor: 
1. Generarea unei clase de excepții existente în caz de excepție pentru care nu există o clasă de excepție standard. 
În exemplul următor se cere ca numărul negativ să fie considerat excepție, dar nu există clasă standard în java care să reprezinte excepții de numere negative. Atunci putem verifica probabilitatea că utilizatorul va introduce număr negativ în bloc try dacă acest lucru se va întâmpla vom genera de exemplu o excepție de tip InputMismatchException()
import java.util.*;
class GenerareExceptie {
int nr=-1;
public static void main (String [] args){
GenerareExceptie ob = new GenerareExceptie();
try {
if (ob.nr<0) throw new InputMismatchException();
}catch (InputMismatchException e) {
System.out.println("Introduceti un numar pozitiv");
}
System.out.println("Continua executia programului!"); }}

2. Crearea unei clase de excepție proprie. Algoritmul pentru a crea propria clasă de excepții vom explora într-o altă postare. 


Rețineți !

1. Cu ajutorul cuvântului rezervat throw avem posibilitatea de a crea explicit un tip de excepție propriu, adică putem crea o instanță excepție, arunca și trata la faza de execuție. Se folosește nemijlocit însoțită de blocul try și operatorul new().

2. Cuvântul rezervat throws ne ajută atunci când dorim să aruncăm, sau transferăm eroarea, astfel încât aceasta să fie tratată de compilator automat, adică eroarea nu va fi tratată de noi explicit într-un bloc try. Cuvântul rezervat throws se scrie în semnătura metodei codul căreia ar putea genera o excepție. Acesta va fi urmat de tipul erorii sau tipurile erorilor ce pot fi generate și de asemenea se poate folosi în semnătura metodei main().

Suplimentar pentru tinerii neliniștitți :) 👌

Mai există o formă a instrucțiunii try destinată în special resurselor care implementează interfața AutoCloseable?

Blocul try-with-resources este o funcționalitate introdusă în Java 7 care permite programatorilor să gestioneze resursele care trebuie închise în mod automat într-un mod elegant și sigur. Acesta este utilizat atunci când lucrăm cu resurse care implementează interfața AutoCloseable, cum ar fi fluxuri de citire de la tastatură, fluxurile de fișiere, conexiunile la baze de date sau alte resurse care trebuie închise explicit. Clasa Scanner este una din acestea. Deci dacă folosim try-with-resources fluxul de citire creat prin instanțirea clasei Scanner va fi închis automat! Minunat 👏
import java.util.*;
class TryCuResurse {
public static void main(String[] args) {
// Specificăm resursa (Scanner) care trebuie închisă automat în blocul try-with-resources
try (Scanner scanner = new Scanner(System.in)) {
while (scanner.hasNext()){
String line = scanner.nextLine();
System.out.println(line);
}} catch (InputMismatchException e) {
e.printStackTrace();}}}

Respectăm cu grijă regula! Un program își finisează execuția doar atunci când utilizatorul își dorește acest lucru! 
Sper că această postare vă este utilă.

Urmează o resursă video din punguța digitală a acestui curs: 




Este binevenit orice comentariu!

Să aveți parte de o zi extraordinară !!!!!