ALGO25 / BLOG

Java: excepții, generice și liste

Învață să validezi ID-uri în Java, să tratezi excepții și să folosești List<Integer>. Exemple complete, intrări invalide și exerciții cu răspunsuri.

Datele primite din exterior nu respectă întotdeauna cerința. În această lecție citim argumente care ar trebui să fie ID-uri pozitive. Păstrăm valorile valide într-o listă tipizată și raportăm fiecare argument invalid fără să ascundem rezultatul celorlalte.

Ce trebuie să știi deja

Recapitulează clasele și metodele. Folosim Java 21. Politica exercițiului este „continuăm după o intrare invalidă”. Alte aplicații pot cere respingerea întregului lot; alegerea trebuie să apară în contract, nu să fie un efect accidental al blocurilor try și catch.

Un ID valid este un întreg strict pozitiv reprezentabil ca int. Textul abc, valoarea zero, un număr negativ și un număr prea mare sunt intrări invalide. Acceptăm numai forma înțeleasă de Integer.parseInt; nu eliminăm automat spații și nu interpretăm zecimale.

Programul complet

import java.util.ArrayList;
import java.util.List;

public class Main {
    static int positiveId(String raw) {
        int id = Integer.parseInt(raw);
        if (id <= 0) {
            throw new IllegalArgumentException("ID must be positive");
        }
        return id;
    }

    public static void main(String[] args) {
        List<Integer> ids = new ArrayList<>();
        for (String raw : args) {
            try {
                ids.add(positiveId(raw));
            } catch (IllegalArgumentException exception) {
                System.out.println("Invalid: " + raw);
            }
        }
        System.out.println(ids);
    }
}

Compilează cu javac Main.java, apoi rulează java Main 12 x -3 7. Rezultatul este Invalid: x, Invalid: -3, apoi [12, 7], pe trei linii. Fără argumente, rezultatul este []. Lista păstrează ordinea valorilor valide și permite duplicate.

De ce List, nu List

Parametrul de tip spune ce fel de elemente acceptă lista. Genericele Java folosesc tipuri referință, deci scriem Integer, nu int. Compilatorul introduce conversia dintre valoarea primitivă și obiectul wrapper atunci când adăugăm numărul în listă. Această conversie se numește autoboxing.

O listă poate crește; un array are lungime fixă. Tipul declarat List<Integer> exprimă contractul de listă, iar ArrayList este implementarea aleasă. Nu înseamnă că orice operație are același cost sau că lista este sigură pentru modificare simultană din mai multe fire.

Excepția separă rezultatul de eșec

positiveId returnează un număr valid sau aruncă o excepție. Integer.parseInt poate arunca NumberFormatException, care este un subtip al IllegalArgumentException. Pentru valorile nenegociate de contract, precum zero, aruncăm explicit IllegalArgumentException. De aceea un singur catch acoperă cele două situații ale exercițiului.

Nu prindem toate excepțiile posibile cu Exception doar ca programul să pară stabil. O eroare neașteptată trebuie investigată. În același timp, nu afișăm utilizatorului automat un stack trace complet când acesta a introdus un text invalid. Mesajul pentru utilizator și informația de diagnostic au roluri diferite.

Java distinge excepții checked, pe care codul trebuie să le declare sau să le trateze, de excepții unchecked. Acestea din urmă includ subclasele RuntimeException. Alegerea modelului într-un API trebuie să exprime ce fel de eșec poate gestiona apelantul; nu este o competiție pentru a elimina toate declarațiile throws.

Nu folosi null pentru orice absență

Lista goală înseamnă că nu avem ID-uri acceptate. Nu returnăm null în loc de listă goală, fiindcă am forța fiecare apelant să ghicească semnificația. Într-o căutare a unei singure valori, Optional<T> poate exprima absența, dar nu înlocuiește automat excepțiile, validarea sau toate câmpurile nullable.

Pentru resurse precum fișiere și conexiuni, închiderea trebuie tratată separat. try-with-resources este mecanismul potrivit pentru obiecte AutoCloseable. Lista din acest exemplu nu este o resursă care trebuie închisă.

Exersează

  1. Rulează cu 1 1 2. Rezultatul este [1, 1, 2]. Dacă cerința interzice duplicatele, o listă singură nu rezolvă acea regulă.
  2. Rulează cu 2147483648. Valoarea depășește int, deci este raportată invalidă, iar lista rămâne goală.
  3. Schimbă politica astfel încât primul argument invalid să oprească întregul lot. Explică unde muți tratarea erorii și ce rezultat mai poate fi observat de apelant.

Verifică înainte să continui

Trebuie să poți explica tipul elementelor, ordinea, duplicatele și ce excepții tratezi. Continuă cu egalitate și colecții, apoi cu colecții și streamuri. După aceste verificări, începe primul proiect Spring Boot.

Întrebări frecvente

De ce NumberFormatException este prinsă aici?

Fiindcă moștenește IllegalArgumentException. Relația dintre tipuri contează în alegerea unui bloc catch.

ArrayList elimină duplicatele?

Nu. Păstrează fiecare element adăugat, inclusiv valori egale.

Este o listă goală o eroare?

Nu în contractul acestui program. Este rezultatul normal când nu există argumente valide.

Genericele acceptă direct int?

Nu. Folosește tipul wrapper Integer pentru elementele acestei liste.

Trebuie să prind orice excepție lângă linia care o produce?

Nu. Trateaz-o la nivelul care poate lua o decizie utilă. Aici fiecare argument este independent, deci tratarea locală corespunde cerinței.

Surse

Excepții Java, generice și Integer, consultate la 13 octombrie 2026.