Math.addExact în Java

Adunare, scădere, înmulțire, incrementare și negare care aruncă ArithmeticException la overflow în loc să dea rezultat greșit.

Sintaxă
static int addExact(int x, int y)   // și long
static int subtractExact(int x, int y)
static int multiplyExact(int x, int y)
static int incrementExact(int a)
static int decrementExact(int a)
static int negateExact(int a)

Ce face Math.addExact

Operațiile obișnuite cu int și long nu verifică depășirea: dacă rezultatul nu încape, se „întoarce” la capătul opus și programul continuă cu o valoare greșită. Metodele Exact fac aceleași calcule, dar aruncă ArithmeticException cu mesajul integer overflow (sau long overflow).

addExact(x, y) este x + y, subtractExact este x - y, multiplyExact este x * y, incrementExact(a) este a + 1, decrementExact(a) este a - 1, iar negateExact(a) este -a (overflow doar pentru MIN_VALUE). Folosește-le când lucrezi cu sume de bani, contoare sau dimensiuni, unde un rezultat greșit este mai rău decât o eroare.

Parametri

Parametru Descriere
x, y Operanzii.
a Pentru variantele cu un argument: valoarea de modificat.

Ce returnează

Rezultatul exact, de tip int sau long.

Exemple

Exemplul 1: Overflow tăcut față de excepție

public class Main {
    public static void main(String[] args) {
        int sold = 2_000_000_000;
        int depunere = 500_000_000;
        System.out.println("Cu +: " + (sold + depunere));
        try {
            System.out.println(Math.addExact(sold, depunere));
        } catch (ArithmeticException e) {
            System.out.println("addExact: " + e.getMessage());
        }
        System.out.println(Math.addExact(1500L, 2500L));
    }
}

Rezultat

Cu +: -1794967296
addExact: integer overflow
4000

Exemplul 2: Toate operațiile Exact

public class Main {
    static void incearca(String nume, java.util.function.IntSupplier calcul) {
        try {
            System.out.println(nume + " = " + calcul.getAsInt());
        } catch (ArithmeticException e) {
            System.out.println(nume + ": " + e.getMessage());
        }
    }

    public static void main(String[] args) {
        int max = Integer.MAX_VALUE;
        int min = Integer.MIN_VALUE;
        incearca("subtractExact(100, 30)", () -> Math.subtractExact(100, 30));
        incearca("subtractExact(min, 1)", () -> Math.subtractExact(min, 1));
        incearca("multiplyExact(46341, 46341)", () -> Math.multiplyExact(46341, 46341));
        incearca("incrementExact(41)", () -> Math.incrementExact(41));
        incearca("incrementExact(max)", () -> Math.incrementExact(max));
        incearca("decrementExact(min)", () -> Math.decrementExact(min));
        incearca("negateExact(25)", () -> Math.negateExact(25));
        incearca("negateExact(min)", () -> Math.negateExact(min));
    }
}

Rezultat

subtractExact(100, 30) = 70
subtractExact(min, 1): integer overflow
multiplyExact(46341, 46341): integer overflow
incrementExact(41) = 42
incrementExact(max): integer overflow
decrementExact(min): integer overflow
negateExact(25) = -25
negateExact(min): integer overflow

Exemplul 3: Valoarea unei comenzi mari

Prețul este în bani (întreg); înmulțirea cu o cantitate mare poate depăși int.

public class Main {
    static String total(int pretBani, int cantitate) {
        try {
            int bani = Math.multiplyExact(pretBani, cantitate);
            return bani / 100 + " lei";
        } catch (ArithmeticException e) {
            return "comandă prea mare pentru int";
        }
    }

    public static void main(String[] args) {
        System.out.println(total(1250, 40));
        System.out.println(total(1250, 2_000_000));
        System.out.println(Math.multiplyExact(1250L, 2_000_000L) / 100 + " lei (cu long)");
    }
}

Rezultat

500 lei
comandă prea mare pentru int
25000000 lei (cu long)

Greșeli frecvente

  • Prinzi ArithmeticException și continui ca și cum nimic nu s-ar fi întâmplat. Excepția înseamnă că tipul ales este prea mic: treci la long sau la BigInteger.
  • Folosești addExact cu double: metodele există doar pentru int și long. Numerele double nu dau overflow, ci Infinity.

Comenzi înrudite

  • Math.toIntExact: Transformă un long în int și aruncă ArithmeticException dacă valoarea nu încape, în loc să o taie în tăcere.
  • Math.multiplyFull: multiplyFull înmulțește două int-uri cu rezultat long complet; multiplyHigh dă jumătatea de sus a produsului a două long-uri.
  • Math.powExact: Putere și înmulțire întreagă exactă (Java 25): rezultat int/long sau ArithmeticException la overflow, inclusiv pentru numere fără semn.
  • Integer: Clasa wrapper pentru int: obiectul care învelește un număr întreg, plus constante și metode de conversie.
  • Math.floorDivExact: Variante ale împărțirii întregi care aruncă ArithmeticException la overflow, în loc să returneze un rezultat greșit.