We performed a migration to Java 11 and a bug fix about negative symbol for negative numbers in Java ruined our implementation. This article describes the situation and the lessons learned.

In the middle of a migration of a project to Java 11 a very curious scenario has appeared. We face a bug while dealing with negative numbers. We have a function to convert a positive number to negative. The implementation was working fine for Java 8 but not for Java 11:

public String negativeNumber(int number) {
    return "-" + number;

The error appeared while trying to parse the numbers generated with that function:

public Number parse(String number) throws ParseException {
    return fmt.parse(number)

More precisely, it was throwing the following exception:

Unparseable number: "-1"
java.text.ParseException: Unparseable number: "-1"
	at java.base/java.text.NumberFormat.parse(NumberFormat.java:431)
	at SwedishNegativeSymbol.shouldParseNegativeNumberButFailsOnJava11(SwedishNegativeSymbol.java:23)

The investigation and debug led us to compare our negative symbol with the one expected by the NumberFormat:

public void shouldUseSameNegativeSymbol() {
    String expectedNegativeSymbol = fmt.getNegativePrefix();
    String negativeSymbol = negate(1).substring(0, 1);
    assertEquals("Negative symbols do not match!", expectedNegativeSymbol, negativeSymbol);

And… surprise, the test pass on Java 8 but not in Java 11:

Negative symbols do not match! expected:<[−]> but was:<[-]>
Expected :−
Actual   :-

org.junit.ComparisonFailure: Negative symbols do not match! expected:<[−]> but was:<[-]>
	at org.junit.Assert.assertEquals(Assert.java:115)
	at SwedishNegativeSymbol.shouldUseSameNegativeSymbol(SwedishNegativeSymbol.java:35)

WTF!. Why on earth the negative symbol do not match? The response is here: JDK-8214926.

It looks like the negative symbol returned in Java 8 was wrong and Java authors decided to fix that in Java11. The two characters are visually very similar:

The solution was straightforward: use the negative symbol provided by NumberFormat

public String negativeNumberWorkingOnJava11(int number) {
    DecimalFormat fmt = (DecimalFormat) NumberFormat.getInstance(Locale.forLanguageTag("se-sv"));
    return fmt.getNegativePrefix() + number;

Now the test passes both in Java 8 and Java 11.

The lesson learned was important: DO NOT HARDCODE NEGATIVE SYMBOL!

You can find the source code here: SwedishNegativeSymbol.java