title: Does the JLS require inlining of final String constants?
body: <p>I ran into an issue while manipulating some bytecode, where a certain <code>final</code> <code>String</code> constant was not inlined by the java compiler (Java 8), see the example below:</p>
  
  <pre><code>public class MyTest
  {
    private static final String ENABLED  = "Y";
    private static final String DISABLED = "N";
  
    private static boolean isEnabled(String key) {
        return key.equals("A");
    }
  
    private static String getString(String key, String value) {
        return key + value;
    }
  
    public static void main(String[] args) throws Exception {
      String flag = getString("F", isEnabled("A") ? ENABLED : DISABLED);
      System.out.println(flag);
  
      String flag2 = getString("F", isEnabled("A") ? ENABLED : DISABLED);
      System.out.println(flag2);
    }
  }
  </code></pre>
  
  <p>Resulting bytecode with javac (1.8.0_101)</p>
  
  <pre><code>public static void main(java.lang.String[]) throws java.lang.Exception;
      descriptor: ([Ljava/lang/String;)V
      flags: ACC_PUBLIC, ACC_STATIC
      Code:
        stack=2, locals=3, args_size=1
           0: ldc           #8                  // String F
           2: ldc           #2                  // String A
           4: invokestatic  #9                  // Method isEnabled:(Ljava/lang/String;)Z
           7: ifeq          16
          10: getstatic     #10                 // Field ENABLED:Ljava/lang/String;
          13: goto          19
          16: getstatic     #11                 // Field DISABLED:Ljava/lang/String;
          19: invokestatic  #12                 // Method getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
          22: astore_1
          23: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
          26: aload_1
          27: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          30: ldc           #8                  // String F
          32: ldc           #2                  // String A
          34: invokestatic  #9                  // Method isEnabled:(Ljava/lang/String;)Z
          37: ifeq          46
          40: getstatic     #10                 // Field ENABLED:Ljava/lang/String;
          43: goto          49
          46: getstatic     #11                 // Field DISABLED:Ljava/lang/String;
          49: invokestatic  #12                 // Method getString:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
          52: astore_2
          53: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
          56: aload_2
          57: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          60: return
  </code></pre>
  
  <p>You can see that the second time the fields <code>ENABLED</code> and <code>DISABLED</code> are being accessed, the compiler did not inline their values (using <code>ldc</code>), but instead used <code>getstatic</code> to access the field directly. Testing it with other compilers (Java 7, Eclipse) did not trigger the same behavior and the constants were always inlined.</p>
  
  <p>Can this be considered a compiler bug, or is it allowed to <em>not</em> inline string constants all the time according to the JLS?</p>