Implementing String to int (atoi) in Java
All in all, that's a pretty good implementation in a number of key details.

Using the Character.isDigit() and Character.getNumericValue() methods are good to see.

The Math.* methods that handle the overflow conditions are good too.

I am not sure if you intended it, but you also correctly handle an obscure edge-case in 32-bit signed integer systems (not just Java), where Integer.MIN_VALUE is not the same as - Integer.MAX_VALUE ... and your code actually gets it right for an exact input of the text "-2147483648"

So, you have good details in your code.... and I can't see any broken edge-cases.

My only recommendation would be that a state-machine may make things simpler... with just one loop..... but the state-machine may be a bit messy too, although I think it works out better in the long run...

public static int rlAtoi(String str) {
    boolean started = false;
    boolean negative = false;
    int result = 0;
    try {
        for (char c : str.toCharArray()) {
            if (!started &amp;&amp; Character.isWhitespace(c)) {
                // great, ignore it.
            } else if (!started &amp;&amp; (c == '+' || c == '-')) {
                // great, a sign
                negative = c == '-';
                started = true;
            } else if (Character.isDigit(c)) {
                result = Math.multiplyExact(result, 10);
                result = Math.addExact(result, Character.getNumericValue(c));
                started = true;
            } else {
                // done....
                break;
            }
        }
    } catch (ArithmeticException e) {
        return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE;
    }
    return negative ? -result : result;
}


Note that in a raw performance benchmark, I suspect your solution will be (slightly) faster, but I prefer readability over small incremental performance gains, unless performance is extremely critical.