Skip to content

Instantly share code, notes, and snippets.

@renatoathaydes
Last active October 24, 2021 08:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renatoathaydes/a18fcd509115df66efecb1b9cfcc6dc9 to your computer and use it in GitHub Desktop.
Save renatoathaydes/a18fcd509115df66efecb1b9cfcc6dc9 to your computer and use it in GitHub Desktop.
Using static variables in local scope in Java.
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
check("a");
check("b");
}
static Pattern compile(String pattern) {
System.out.println("compile(" + pattern + ")");
return Pattern.compile(pattern);
}
static void check(String string) {
// Compiling the pattern only once: Good
// Keeping the pattern local to the method: Good
// Capturing scope: Egh...
var patterns = new Object() {
static final Pattern P_CHECK = compile("a");
};
System.out.println("check(" + string + "): "
+ patterns.P_CHECK.matcher(string).find());
}
}
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
check("a");
check("b");
}
static Pattern compile(String pattern) {
System.out.println("compile(" + pattern + ")");
return Pattern.compile(pattern);
}
static void check(String string) {
// Compiling the pattern only once: Good
// Keeping the pattern local to the method: Good
// Does not capture the scope: Good
class Patterns {
static final Pattern P_CHECK = compile("a");
}
System.out.println("check(" + string + "): "
+ Patterns.P_CHECK.matcher(string).find());
}
}
@renatoathaydes
Copy link
Author

Bytecode of the second version:

▶ javap -c Test\$1Patterns
Compiled from "Test.java"
class Test$1Patterns {
  static final java.util.regex.Pattern P_CHECK;

  Test$1Patterns();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  static {};
    Code:
       0: ldc           #7                  // String a
       2: invokestatic  #9                  // Method Test.compile:(Ljava/lang/String;)Ljava/util/regex/Pattern;
       5: putstatic     #15                 // Field P_CHECK:Ljava/util/regex/Pattern;
       8: return
}

▶ javap -c Test           
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #7                  // String a
       2: invokestatic  #9                  // Method check:(Ljava/lang/String;)V
       5: ldc           #15                 // String b
       7: invokestatic  #9                  // Method check:(Ljava/lang/String;)V
      10: return

  static java.util.regex.Pattern compile(java.lang.String);
    Code:
       0: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: invokedynamic #23,  0             // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
       9: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      12: aload_0
      13: invokestatic  #32                 // Method java/util/regex/Pattern.compile:(Ljava/lang/String;)Ljava/util/regex/Pattern;
      16: areturn

  static void check(java.lang.String);
    Code:
       0: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: getstatic     #38                 // Field Test$1Patterns.P_CHECK:Ljava/util/regex/Pattern;
       7: aload_0
       8: invokevirtual #44                 // Method java/util/regex/Pattern.matcher:(Ljava/lang/CharSequence;)Ljava/util/regex/Matcher;
      11: invokevirtual #48                 // Method java/util/regex/Matcher.find:()Z
      14: invokedynamic #54,  0             // InvokeDynamic #1:makeConcatWithConstants:(Ljava/lang/String;Z)Ljava/lang/String;
      19: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      22: return
}

@renatoathaydes
Copy link
Author

Bytcode of the first version:

▶ javap -c Test\$1 
Compiled from "Test.java"
class Test$1 {
  static final java.util.regex.Pattern P_CHECK;

  Test$1();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  static {};
    Code:
       0: ldc           #7                  // String a
       2: invokestatic  #9                  // Method Test.compile:(Ljava/lang/String;)Ljava/util/regex/Pattern;
       5: putstatic     #15                 // Field P_CHECK:Ljava/util/regex/Pattern;
       8: return
}

▶ javap -c Test
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #7                  // String a
       2: invokestatic  #9                  // Method check:(Ljava/lang/String;)V
       5: ldc           #15                 // String b
       7: invokestatic  #9                  // Method check:(Ljava/lang/String;)V
      10: return

  static java.util.regex.Pattern compile(java.lang.String);
    Code:
       0: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0
       4: invokedynamic #23,  0             // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
       9: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      12: aload_0
      13: invokestatic  #32                 // Method java/util/regex/Pattern.compile:(Ljava/lang/String;)Ljava/util/regex/Pattern;
      16: areturn

  static void check(java.lang.String);
    Code:
       0: new           #38                 // class Test$1
       3: dup
       4: invokespecial #40                 // Method Test$1."<init>":()V
       7: astore_1
       8: getstatic     #17                 // Field java/lang/System.out:Ljava/io/PrintStream;
      11: aload_0
      12: aload_1
      13: pop
      14: getstatic     #41                 // Field Test$1.P_CHECK:Ljava/util/regex/Pattern;
      17: aload_0
      18: invokevirtual #45                 // Method java/util/regex/Pattern.matcher:(Ljava/lang/CharSequence;)Ljava/util/regex/Matcher;
      21: invokevirtual #49                 // Method java/util/regex/Matcher.find:()Z
      24: invokedynamic #55,  0             // InvokeDynamic #1:makeConcatWithConstants:(Ljava/lang/String;Z)Ljava/lang/String;
      29: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      32: return
}

The generated class Test$1 is identical to the Test$Patterns class, but the check implementation is unnecessarily creating a new instance of Test$1, resulting in 8 extra, unnecessary bytecode instructions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment