This is an old revision of the document!


Breviar 13

1. Fluxuri (Streams)

1.1 Introducere

Dennis Ritchie implementează în 1984 primul sistem I/O pe bază de stream în cadrul sistemului de operare Unix. Acest concept are la bază crearea unui canal de comunicație între două entități: sursă și destinație. Sursa scrie informații în canalul de comunicație, iar destinația poate să citească aceste date, canalul permițând trecerea fluxului de date într-o singură direcție.

Clasificarea fluxurilor:

După direcția canalului de comunicație:

  • fluxuri de intrare (pentru citirea datelor)
  • fluxuri de ieșire (pentru scrierea datelor)

După tipul de date pe care le operează:

  • fluxuri de octeți (transfer serial pe 8 biți)
  • fluxuri de caractere (transfer serial pe 16 biți)

După acțiunea lor:

  • fluxuri primare de citire/scriere a datelor
  • fluxuri pentru procesarea datelor

Datorită faptului că există două direcții de comunicare, există două tipuri mari de stream-uri pentru orice nod de comunicație: input stream și output stream. Tastatura ar fi un exemplu de input stream, iar monitorul un output stream. Sursa și destinația nu trebuie să fie neapărat periferice, ele pot fi și module soft.

1.2 Fluxuri de octeți

Programele folosesc fluxuri de octeți pentru a citi sau scrie date pe 8 biți (un octet). Fluxurile la nivel de octet utilizează două ierarhii având drept clase rădăcină: InputStream și OutputStream.

Cele mai utilizate clase sunt FileInputStream și FileOutputStream.

public class Copy {
    private String input, output;
 
    public Copy(String input, String output) {
        this.input = input;
        this.output = output;
    }
 
    public void copyFile() {
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(input);
            out = new FileOutputStream(output);
            while (in.available() > 0)
                out.write(in.read());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) out.close();
                if (in != null) in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

IMPORTANT! Fișierele text trebuie să se afle în folderul rădăcină al proiectului care conține clasele care prelucrează informația din aceste fișiere.

1.3 Fluxuri de caractere

Limbajul Java stochează valorile de tip caracter folosind convenții Unicode. Fluxurile de caractere I/O își translatează automat formatul intern de la setul de caractere locale.

Toate clasele de fluxuri de caractere moștenesc clasele Reader și Writer. Pentru operațiile I/O cu fișiere: FileReader și FileWriter.

public class Read {
    private String input;
 
    public Read(String input) {
        this.input = input;
    }
 
    public void read() {
        FileReader stream = null;
        BufferedReader br = null;
        try {
            stream = new FileReader(input);
            br = new BufferedReader(stream);
            String line = br.readLine();
            while (line != null) {
                System.out.println(line);
                line = br.readLine();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (stream != null) stream.close();
                if (br != null) br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Observație: Obiectul BufferedReader creează un flux de intrare a caracterelor cu stocare temporară (și posibilitate de citire a caracterelor sub formă de linii) din fluxul de intrare a caracterelor primit ca parametru.

1.4 Fluxuri cu zone tampon (Buffer)

Pentru un flux I/O fără zone tampon, fiecare cerere de citire sau scriere este administrată direct de sistemul de operare. Aceasta face ca programul să fie mai puțin eficient, deoarece fiecare cerere declanșează accesul la disc, activitate în rețea sau alte operații care consumă timp.

Pentru a reduce timpul de procesare, platforma Java implementează fluxuri I/O cu zone tampon:

  • Fluxurile de intrare cu zone tampon citesc datele dintr-o zonă de memorie cunoscută ca buffer
  • API-ul de intrare este apelat numai când tamponul este gol
  • Similar, fluxurile de ieșire scriu datele în zona de tampon și API-ul de ieșire este apelat când tamponul este plin

Un program poate converti un flux fără zonă tampon într-un flux cu zonă tampon astfel: un obiect de tip flux fără zonă tampon este trecut ca argument unui constructor pentru o clasă de tip flux cu zonă tampon.

1.5 Fluxuri standard

Limbajul Java pune la dispoziția utilizatorului trei fluxuri standard pentru comunicare cu consola:

Flux Descriere Referință
Standard Input pentru citirea datelor System.in (InputStream)
Standard Output pentru afișarea datelor System.out (PrintWriter)
Standard Error pentru afișarea erorilor System.err (PrintWriter)

Observație: Nu este necesară instanțierea acestor trei stream-uri, deoarece ele se deschid automat înaintea execuției aplicației. De asemenea, acestea nici nu se închid prin apelul metodei close().

Exemplu cu InputStreamReader și BufferedReader:

public class Suma {
    int a, b;
 
    public void read() {
        InputStreamReader stream = null;
        BufferedReader br = null;
        try {
            stream = new InputStreamReader(System.in);
            br = new BufferedReader(stream);
            String line = br.readLine();
            a = Integer.parseInt(line);
            line = br.readLine();
            b = Integer.parseInt(line);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (stream != null) stream.close();
                if (br != null) br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Exemplu cu Scanner:

public class Test {
    public static void main(String args[]) throws Exception {
        Scanner in = new Scanner(System.in);
        int a, b;
        a = in.nextInt();
        b = in.nextInt();
        int result = a + b;
        System.out.println(a + " + " + b + " = " + result);
        in.close();
    }
}

2. Funcționale

2.1 Introducere

În paradigma funcțională, funcțiile sunt valori de ordinul 1 ce pot fi manipulate ca orice altă valoare. Funcționalele sunt funcții care manipulează alte funcții, primindu-le ca argumente sau returnându-le ca rezultat.

2.2 Lista funcționalelor

foldl(function, init, list)

Returnează rezultatul aplicării funcției function pe rând asupra unui element din listă și a unui acumulator init. Ordinea folosirii elementelor din listă este de la stânga la dreapta.

foldl(f(x, y) = x + y, 5, [0, 1, 2, 3])
= f(f(f(f(5, 0), 1), 2), 3)
= f(f(f(5, 1), 2), 3)
= f(f(6, 2), 3)
= f(8, 3)
= 11
foldr(function, init, list)

Are un comportament similar cu foldl, însă ordinea folosirii elementelor din listă este de la dreapta la stânga.

foldr(f(x, y) = y, 4, [0, 1, 2, 3])
= f(0, f(1, f(2, f(3, 4))))
= f(0, f(1, f(2, 4)))
= f(0, f(1, 4))
= f(0, 4)
= 0
map(function, list)

Returnează lista rezultatelor aplicării unei funcții f asupra fiecărui element dintr-o listă.

map(f(x) = 2*x, [0, 1, 2, 3]) => [0, 2, 4, 6]
filter(predicat, list)

Returnează lista elementelor dintr-o listă care satisfac un predicat p. Un predicat este o funcție care are un rezultat de tip Boolean.

filter(f(x) = x % 2 == 0, [0, 1, 2, 3]) => [0, 2]
reduce(function, list)

Aplică funcția pentru primele două elemente din listă, apoi pentru rezultatul obținut anterior și următorul element și tot așa.

reduce(f(x, y) = x + y, [47, 11, 42, 13])
= f(f(f(47, 11), 42), 13)
= f(f(58, 42), 13)
= f(100, 13)
= 113
all(predicat, list)

Primește un predicat și verifică dacă toate elementele din listă satisfac predicatul.

all(f(x) = x > 0, [0, 1, 2, 3])   => False  (0 nu e > 0)
all(f(x) = x >= 0, [0, 1, 2, 3]) => True
any(predicat, list)

Primește un predicat și verifică dacă există cel puțin un element în listă care satisface predicatul.

any(f(x) = x < 0, [1, 2, 3, 4])   => False
any(f(x) = x % 2 == 0, [1, 2, 3]) => True   (2 e par)

2.3 Rezumat funcționale

Funcțională Descriere Exemplu
foldl Agregare stânga→dreapta cu acumulator foldl(+, 0, [1,2,3]) = 6
foldr Agregare dreapta→stânga cu acumulator foldr(-, 0, [1,2,3]) = 2
map Transformă fiecare element map(x→x*2, [1,2]) = [2,4]
filter Păstrează elementele care satisfac predicatul filter(par, [1,2,3]) = [2]
reduce Agregare fără acumulator inițial reduce(+, [1,2,3]) = 6
all Toate satisfac predicatul? all(>0, [1,2]) = True
any Există cel puțin unul care satisface? any(<0, [1,2]) = False
poo/breviare/breviar-13.1768199496.txt.gz · Last modified: 2026/01/12 08:31 by george.tudor1906
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0