Close

Syntactic Sugar

[Updated: Oct 2, 2018, Created: Oct 2, 2018]

Software Engineering Java 

In a programming language syntactic sugar is a convenient syntax/construct which makes things easier for the programmer.

Java language provides many syntactic constructs. For example consider following Java enum class:

public enum EnumTest {
  ElementA, ElementB, ElementC
}

Let's compile above class and analyze compiled bytecode via javap:

D:\java-syntactic-sugar-examples>javac EnumTest.java

D:\java-syntactic-sugar-examples>javap EnumTest
Compiled from "EnumTest.java"
public final class EnumTest extends java.lang.Enum<EnumTest> {
  public static final EnumTest ElementA;
  public static final EnumTest ElementB;
  public static final EnumTest ElementC;
  public static EnumTest[] values();
  public static EnumTest valueOf(java.lang.String);
  static {};
}

The compiler has converted the enum class to a normal Java class extending java.lang.Enum. Each enum element is converted to static final constant of the enclosing class type.

Foreach loop is another example:

public class ForEachLoop {
  public static void main(String[] args) {
      List<Integer> list = List.of(1, 3, 6, 8, 9);
      for (int i : list) {
          System.out.println(i);
      }
  }
}

If we compile above class and analyze the compiled code via javap:

D:\java-syntactic-sugar-examples>javac ForEachLoop.java

D:\java-syntactic-sugar-examples>javap -v ForEachLoop
Classfile /D:/java-syntactic-sugar-examples/src/main/java/ForEachLoop.class
  Last modified Oct 2, 2018; size 876 bytes
  MD5 checksum 3c591f0e683054877602faac8cc45075
  Compiled from "ForEachLoop.java"
public class ForEachLoop
  minor version: 0
  major version: 55
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #11                         // ForEachLoop
  super_class: #12                        // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #12.#24        // java/lang/Object."<init>":()V
   #2 = Methodref          #7.#25         // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #3 = InterfaceMethodref #20.#26        // java/util/List.of:(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/List;
   #4 = InterfaceMethodref #20.#27        // java/util/List.iterator:()Ljava/util/Iterator;
   #5 = InterfaceMethodref #21.#28        // java/util/Iterator.hasNext:()Z
   #6 = InterfaceMethodref #21.#29        // java/util/Iterator.next:()Ljava/lang/Object;
   #7 = Class              #30            // java/lang/Integer
   #8 = Methodref          #7.#31         // java/lang/Integer.intValue:()I
   #9 = Fieldref           #32.#33        // java/lang/System.out:Ljava/io/PrintStream;
  #10 = Methodref          #34.#35        // java/io/PrintStream.println:(I)V
  #11 = Class              #36            // ForEachLoop
  #12 = Class              #37            // java/lang/Object
  #13 = Utf8               <init>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               StackMapTable
  #20 = Class              #38            // java/util/List
  #21 = Class              #39            // java/util/Iterator
  #22 = Utf8               SourceFile
  #23 = Utf8               ForEachLoop.java
  #24 = NameAndType        #13:#14        // "<init>":()V
  #25 = NameAndType        #40:#41        // valueOf:(I)Ljava/lang/Integer;
  #26 = NameAndType        #42:#43        // of:(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/List;
  #27 = NameAndType        #44:#45        // iterator:()Ljava/util/Iterator;
  #28 = NameAndType        #46:#47        // hasNext:()Z
  #29 = NameAndType        #48:#49        // next:()Ljava/lang/Object;
  #30 = Utf8               java/lang/Integer
  #31 = NameAndType        #50:#51        // intValue:()I
  #32 = Class              #52            // java/lang/System
  #33 = NameAndType        #53:#54        // out:Ljava/io/PrintStream;
  #34 = Class              #55            // java/io/PrintStream
  #35 = NameAndType        #56:#57        // println:(I)V
  #36 = Utf8               ForEachLoop
  #37 = Utf8               java/lang/Object
  #38 = Utf8               java/util/List
  #39 = Utf8               java/util/Iterator
  #40 = Utf8               valueOf
  #41 = Utf8               (I)Ljava/lang/Integer;
  #42 = Utf8               of
  #43 = Utf8               (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/List;
  #44 = Utf8               iterator
  #45 = Utf8               ()Ljava/util/Iterator;
  #46 = Utf8               hasNext
  #47 = Utf8               ()Z
  #48 = Utf8               next
  #49 = Utf8               ()Ljava/lang/Object;
  #50 = Utf8               intValue
  #51 = Utf8               ()I
  #52 = Utf8               java/lang/System
  #53 = Utf8               out
  #54 = Utf8               Ljava/io/PrintStream;
  #55 = Utf8               java/io/PrintStream
  #56 = Utf8               println
  #57 = Utf8               (I)V
{
  public ForEachLoop();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=5, locals=4, args_size=1
         0: iconst_1
         1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       .......
}

The above analysis shows that foreach loop has been replaced by java.util.Iterator. The equivalent code would be:

   List<Integer> list = List.of(1, 3, 6, 8, 9);
   Iterator<Integer> itr = list.iterator();
   while(itr.hasNext()) {
       System.out.println(itr.next());
   }


Syntactic sugar is a mean which allows Java to provide new syntax without implementing that on JVM level. The syntactic syntax is converted into another more general or low level construct by the compiler which can be understood by JVM. That way syntactic constructs enable Java compilers to implement new Java language features without changes to the JVM.

See Also