JDK-8282627 : JDK 11 invokedynamic-based string concatenation produces different result than JDK 8
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 11,17
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2022-03-03
  • Updated: 2022-03-03
  • Resolved: 2022-03-03
Related Reports
Duplicate :  
Relates :  
Description
This is a small semantic change of the String "+" operator caused by the invokedynamic-based string concatenation (JDK-8085796). I am not aware that it was mentioned anywhere (like in the "risk" section of JEP 280), so I want to document it.

The following application prints a different result when compiled with JDK 8 and JDK 11:

public class HelloWorld {
    public static void main(String[] args) {
        Handler h = new Handler();
        System.out.println(h + h.incrementAndGet() + h);

        h = new Handler();
        System.out.println(new StringBuilder().append(h).append(h.incrementAndGet()).append(h).toString());
    }
}

class Handler {
    int state;
    
    String incrementAndGet() {
        state++;
        return String.valueOf(state);
    }
    
    @Override
    public String toString() {
        return incrementAndGet();
    }
}


When compiled with JDK 8, using the "+" operator leads to the same bytecode as the explicit usage of StringBuilder, so the output is

123
123

When compiled with JDK 11 or later, the explicit invocation of incrementAndGet() using the "+" operator is executed before the implicit invocation of toString(), therefore the output is

213
123