Exact Absolute Integral Numbers in JDK 15
JDK 15 Early Access Build b18 introduced new methods to the Math and StrictMath classes that will throw ArithmeticException on provided values outside the range supported by the methods without overflow. These methods bring to the concept of “absolute value” in Java what the methods such as Math.addExact, Math.subtractExact, and Math.multiplyExact have brought to basic arithmetic functions.
Prior to JDK 15, Integer.MIN_VALUE and Long.MIN_VALUE caused the respective methods Math.abs and StrictMath.abs to return the same negative number as represented by the MIN_VALUE largest negative possible value. This behavior is described in the Javadoc documentation for the affected methods and is demonstrated by the code shown below (and available on GitHub):
Demonstrating Pre-JDK 15 Absolute Value Methods
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /** * Demonstrates "absExact" methods added to {@link Math} * and {@link StrictMath} with JDK 15 Early Access Build b18 * (JDK-8241374: https://bugs.openjdk.java.net/browse/JDK-8241374). */ public class AbsoluteExactness { public void demonstrateMathAbsInteger( final int integer) { out.println( "Math.abs(" + integer + "): " + Math.abs(integer)); } public void demonstrateMathAbsLong( final long longNumber) { out.println( "Math.abs(" + longNumber + "L): " + Math.abs(longNumber)); } public void demonstrateStrictMathAbsInteger( final int integer) { out.println( "StrictMath.abs(" + integer + "): " + StrictMath.abs(integer)); } public void demonstrateStrictMathAbsLong( final long longNumber) { out.println( "StrictMath.abs(" + longNumber + "L): " + StrictMath.abs(longNumber)); } public static void main( final String[] arguments) { final AbsoluteExactness instance = new AbsoluteExactness(); // Demonstrate pre-JDK 15 Math/StrictMath "abs" functions on minimum values. instance.demonstrateMathAbsInteger(Integer.MIN_VALUE+ 1 ); instance.demonstrateMathAbsInteger(Integer.MIN_VALUE); instance.demonstrateMathAbsLong(Long.MIN_VALUE+ 1 ); instance.demonstrateMathAbsLong(Long.MIN_VALUE); instance.demonstrateStrictMathAbsInteger(Integer.MIN_VALUE+ 1 ); instance.demonstrateStrictMathAbsInteger(Integer.MIN_VALUE); instance.demonstrateStrictMathAbsLong(Long.MIN_VALUE+ 1 ); instance.demonstrateStrictMathAbsLong(Long.MIN_VALUE); } } |
When the above code is executed, the following output is written:
1 2 3 4 5 6 7 8 | Math.abs(- 2147483647 ): 2147483647 Math.abs(- 2147483648 ): - 2147483648 Math.abs(-9223372036854775807L): 9223372036854775807 Math.abs(-9223372036854775808L): - 9223372036854775808 StrictMath.abs(- 2147483647 ): 2147483647 StrictMath.abs(- 2147483648 ): - 2147483648 StrictMath.abs(-9223372036854775807L): 9223372036854775807 StrictMath.abs(-9223372036854775808L): - 9223372036854775808 |
This output demonstrates that the maximum negative allowable value in the int
and long
ranges leads to that same value being returned from the appropriate abs method on Math and StrictMath.
JDK 15 Early Access Build b18 introduces absExact methods that throw ArithmeticException in this case instead of returning the negative value. This is demonstrated with the following code (also available on GitHub):
Demonstrating JDK 15-Introduced absExact Methods
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | public class AbsoluteExactness { public void demonstrateMathAbsExactInteger( final int integer) { try { out.println( "Math.absExact(" + integer + "): " + Math.absExact(integer)); } catch (ArithmeticException exception) { err.println( "Math.absExact(" + integer + "): " + exception); } } public void demonstrateMathAbsExactLong( final long longNumber) { try { out.println( "Math.absExact(" + longNumber + "L): " + Math.absExact(longNumber)); } catch (ArithmeticException exception) { err.println( "Math.absExact(" + longNumber + "L): " + exception); } } public void demonstrateStrictMathAbsExactInteger( final int integer) { try { out.println( "StrictMath.absExact(" + integer + "): " + StrictMath.absExact(integer)); } catch (ArithmeticException exception) { err.println( "StrictMath.absExact(" + integer + "):" + exception); } } public void demonstrateStrictMathAbsExactLong( final long longNumber) { try { out.println( "StrictMath.absExact(" + longNumber + "L): " + StrictMath.absExact(longNumber)); } catch (ArithmeticException exception) { err.println( "StrictMath.absExact(" + longNumber + "L): " + exception); } } public static void main( final String[] arguments) { final AbsoluteExactness instance = new AbsoluteExactness(); // Demonstrate JDK 15-introduced Math/StrictMath "absExact" functions // on minimum values. instance.demonstrateMathAbsExactInteger(Integer.MIN_VALUE+ 1 ); instance.demonstrateMathAbsExactInteger(Integer.MIN_VALUE); instance.demonstrateMathAbsExactLong(Long.MIN_VALUE+ 1 ); instance.demonstrateMathAbsExactLong(Long.MIN_VALUE); instance.demonstrateStrictMathAbsExactInteger(Integer.MIN_VALUE+ 1 ); instance.demonstrateStrictMathAbsExactInteger(Integer.MIN_VALUE); instance.demonstrateStrictMathAbsExactLong(Long.MIN_VALUE+ 1 ); instance.demonstrateStrictMathAbsExactLong(Long.MIN_VALUE); } |
The output from this code is shown next and demonstrates the clear exception message that is thrown when the MIN_VALUE is passed to the absExact methods.
1 2 3 4 5 6 7 8 | Math.absExact(- 2147483647 ): 2147483647 Math.absExact(- 2147483648 ): java.lang.ArithmeticException: Overflow to represent absolute value of Integer.MIN_VALUE Math.absExact(-9223372036854775807L): 9223372036854775807 Math.absExact(-9223372036854775808L): java.lang.ArithmeticException: Overflow to represent absolute value of Long.MIN_VALUE StrictMath.absExact(- 2147483647 ): 2147483647 StrictMath.absExact(- 2147483648 ):java.lang.ArithmeticException: Overflow to represent absolute value of Integer.MIN_VALUE StrictMath.absExact(-9223372036854775807L): 9223372036854775807 StrictMath.absExact(-9223372036854775808L): java.lang.ArithmeticException: Overflow to represent absolute value of Long.MIN_VALUE |
I find it generally better to have an exception thrown for a surprising edge case than to have “something” returned that requires me to read the Javadoc to find out what that case is and what is returned in that case. The exception makes it obvious that the edge case was encountered rather than the discovery of a negative number being returned from an absolute value function call only being realized sometime later and “downstream” in the code. If nothing else, the mere presence of the Math.absExact and StrictMath.absExact methods should imply to Java developers that there is some “non-exact” possibilities to consider when using Java’s math libraries to compute an absolute value and that realization might lead to reading the Javadoc to find out what those non-exact cases are.
Published on Java Code Geeks with permission by Dustin Marx, partner at our JCG program. See the original article here: Exact Absolute Integral Numbers in JDK 15 Opinions expressed by Java Code Geeks contributors are their own. |