Java syntax sugar foreach

Source: Internet
Author: User
Tags chop

Java syntax sugar foreach

?? Syntactic sugar is a syntax provided by almost every language to help programmers develop code. It is just a little trick implemented by the compiler, during compilation, developers can perform some processing on these syntaxes using specific bytecode or methods, so that developers can use these syntaxes directly and conveniently. Although these syntactic sugar do not provide substantial functional improvements, they can improve performance, improve syntax rigor, or reduce the chance of coding errors. Java provides a lot of syntactic sugar for users, such as generics, automatic packing, automatic unpacking, foreach loop, variable-length parameters, internal classes, enumeration classes, and assert.
?? This article describes how to parse the foreach and foreach syntax after compilation?
?? First, let's look at an example:

package foreach;import java.util.ArrayList;import java.util.List;public class ForeachTest{    public static void main(String[] args)    {        List
  
    list = new ArrayList<>();        list.add("s1");        list.add("s2");        for(String s : list)        {            System.out.println(s);        }    }}
  

?? Decompile this class:

    javac ForeachTest.java    javap -verbose ForeachTest > f1.txt

?? Open f1.txt and the result is as follows:

Classfile /D:/workspace_jee/JavaTest/src/foreach/ForeachTest.class  Last modified 2016-2-25; size 798 bytes  MD5 checksum c64e6f81f34d1dfc7834ad8d5b3b1801  Compiled from "ForeachTest.java"public class foreach.ForeachTest  SourceFile: "ForeachTest.java"  minor version: 0  major version: 51  flags: ACC_PUBLIC, ACC_SUPERConstant pool:   #1 = Methodref          #14.#26        //  java/lang/Object."
  
   ":()V   #2 = Class              #27            //  java/util/ArrayList   #3 = Methodref          #2.#26         //  java/util/ArrayList."
   
    ":()V   #4 = String             #28            //  s1   #5 = InterfaceMethodref #29.#30        //  java/util/List.add:(Ljava/lang/Object;)Z   #6 = String             #31            //  s2   #7 = InterfaceMethodref #29.#32        //  java/util/List.iterator:()Ljava/util/Iterator;   #8 = InterfaceMethodref #33.#34        //  java/util/Iterator.hasNext:()Z   #9 = InterfaceMethodref #33.#35        //  java/util/Iterator.next:()Ljava/lang/Object;  #10 = Class              #36            //  java/lang/String  #11 = Fieldref           #37.#38        //  java/lang/System.out:Ljava/io/PrintStream;  #12 = Methodref          #39.#40        //  java/io/PrintStream.println:(Ljava/lang/String;)V  #13 = Class              #41            //  foreach/ForeachTest  #14 = Class              #42            //  java/lang/Object  #15 = Utf8               
    
       #16 = Utf8               ()V  #17 = Utf8               Code  #18 = Utf8               LineNumberTable  #19 = Utf8               main  #20 = Utf8               ([Ljava/lang/String;)V  #21 = Utf8               StackMapTable  #22 = Class              #43            //  java/util/List  #23 = Class              #44            //  java/util/Iterator  #24 = Utf8               SourceFile  #25 = Utf8               ForeachTest.java  #26 = NameAndType        #15:#16        //  "
     
      ":()V  #27 = Utf8               java/util/ArrayList  #28 = Utf8               s1  #29 = Class              #43            //  java/util/List  #30 = NameAndType        #45:#46        //  add:(Ljava/lang/Object;)Z  #31 = Utf8               s2  #32 = NameAndType        #47:#48        //  iterator:()Ljava/util/Iterator;  #33 = Class              #44            //  java/util/Iterator  #34 = NameAndType        #49:#50        //  hasNext:()Z  #35 = NameAndType        #51:#52        //  next:()Ljava/lang/Object;  #36 = Utf8               java/lang/String  #37 = Class              #53            //  java/lang/System  #38 = NameAndType        #54:#55        //  out:Ljava/io/PrintStream;  #39 = Class              #56            //  java/io/PrintStream  #40 = NameAndType        #57:#58        //  println:(Ljava/lang/String;)V  #41 = Utf8               foreach/ForeachTest  #42 = Utf8               java/lang/Object  #43 = Utf8               java/util/List  #44 = Utf8               java/util/Iterator  #45 = Utf8               add  #46 = Utf8               (Ljava/lang/Object;)Z  #47 = Utf8               iterator  #48 = Utf8               ()Ljava/util/Iterator;  #49 = Utf8               hasNext  #50 = Utf8               ()Z  #51 = Utf8               next  #52 = Utf8               ()Ljava/lang/Object;  #53 = Utf8               java/lang/System  #54 = Utf8               out  #55 = Utf8               Ljava/io/PrintStream;  #56 = Utf8               java/io/PrintStream  #57 = Utf8               println  #58 = Utf8               (Ljava/lang/String;)V{  public foreach.ForeachTest();    flags: ACC_PUBLIC    Code:      stack=1, locals=1, args_size=1         0: aload_0                1: invokespecial #1                  // Method java/lang/Object."
      
       ":()V 4: return LineNumberTable: line 6: 0 public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=4, args_size=1 0: new #2 // class java/util/ArrayList 3: dup 4: invokespecial #3 // Method java/util/ArrayList."
       
        ":()V 7: astore_1 8: aload_1 9: ldc #4 // String s1 11: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z 16: pop 17: aload_1 18: ldc #6 // String s2 20: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z 25: pop 26: aload_1 27: invokeinterface #7, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 32: astore_2 33: aload_2 34: invokeinterface #8, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 39: ifeq 62 42: aload_2 43: invokeinterface #9, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 48: checkcast #10 // class java/lang/String 51: astore_3 52: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 55: aload_3 56: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 59: goto 33 62: return LineNumberTable: line 10: 0 line 11: 8 line 12: 17 line 14: 26 line 16: 52 line 17: 59 line 18: 62 StackMapTable: number_of_entries = 2 frame_type = 253 /* append */ offset_delta = 33 locals = [ class java/util/List, class java/util/Iterator ] frame_type = 250 /* chop */ offset_delta = 28}
       
      
     
    
   
  

?? There is a lot of decompiled content and it doesn't matter if you don't understand it. The key is to see the Iterator mark. In fact, if you use the foreach syntax for objects that implement the Iterable interface, the compiler converts the for keyword to the target iterator.
?? The above code is converted into the following code:

Package foreach; import java. util. arrayList; import java. util. list; public class ForeachTest {// The Compiler adds a default constructor to the class that does not display the constructor. This process is the public ForeachTest () completed in the "Semantic Analysis" phase () {super ();} public static void main (String [] args) {List
  
   
List = new ArrayList <> (); list. add ("s1"); list. add ("s2"); for (java. util. iterator I $ = list. iterator (); I $. hasNext ();) {String s = (String) I $. next (); {System. out. println (s );}}}}
  

Note: If you want to use the foreach syntax sugar for your custom class, you must implement the Iterable interface.

?? Careful friends may notice that arrays in java can also use the foreach syntax sugar, but arrays do not implement the Iterable interface.
?? Here is another example:

package foreach;public class ForeachTest2{    public static void main(String[] args)    {        String arr[] = {"s1","s2"};        for(String s:arr)        {            System.out.println(s);        }    }}

?? Decompilation result:

Classfile /D:/workspace_jee/JavaTest/src/foreach/ForeachTest2.class  Last modified 2016-2-25; size 581 bytes  MD5 checksum 51656b3d3812c5ae3977fffd897a3441  Compiled from "ForeachTest2.java"public class foreach.ForeachTest2  SourceFile: "ForeachTest2.java"  minor version: 0  major version: 51  flags: ACC_PUBLIC, ACC_SUPERConstant pool:   #1 = Methodref          #8.#19         //  java/lang/Object."
  
   ":()V   #2 = Class              #20            //  java/lang/String   #3 = String             #21            //  s1   #4 = String             #22            //  s2   #5 = Fieldref           #23.#24        //  java/lang/System.out:Ljava/io/PrintStream;   #6 = Methodref          #25.#26        //  java/io/PrintStream.println:(Ljava/lang/String;)V   #7 = Class              #27            //  foreach/ForeachTest2   #8 = Class              #28            //  java/lang/Object   #9 = Utf8               
   
      #10 = Utf8               ()V  #11 = Utf8               Code  #12 = Utf8               LineNumberTable  #13 = Utf8               main  #14 = Utf8               ([Ljava/lang/String;)V  #15 = Utf8               StackMapTable  #16 = Class              #29            //  "[Ljava/lang/String;"  #17 = Utf8               SourceFile  #18 = Utf8               ForeachTest2.java  #19 = NameAndType        #9:#10         //  "
    
     ":()V  #20 = Utf8               java/lang/String  #21 = Utf8               s1  #22 = Utf8               s2  #23 = Class              #30            //  java/lang/System  #24 = NameAndType        #31:#32        //  out:Ljava/io/PrintStream;  #25 = Class              #33            //  java/io/PrintStream  #26 = NameAndType        #34:#35        //  println:(Ljava/lang/String;)V  #27 = Utf8               foreach/ForeachTest2  #28 = Utf8               java/lang/Object  #29 = Utf8               [Ljava/lang/String;  #30 = Utf8               java/lang/System  #31 = Utf8               out  #32 = Utf8               Ljava/io/PrintStream;  #33 = Utf8               java/io/PrintStream  #34 = Utf8               println  #35 = Utf8               (Ljava/lang/String;)V{  public foreach.ForeachTest2();    flags: ACC_PUBLIC    Code:      stack=1, locals=1, args_size=1         0: aload_0                1: invokespecial #1                  // Method java/lang/Object."
     
      ":()V         4: return              LineNumberTable:        line 3: 0  public static void main(java.lang.String[]);    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=4, locals=6, args_size=1         0: iconst_2               1: anewarray     #2                  // class java/lang/String         4: dup                    5: iconst_0               6: ldc           #3                  // String s1         8: aastore                9: dup                   10: iconst_1              11: ldc           #4                  // String s2        13: aastore               14: astore_1              15: aload_1               16: astore_2              17: aload_2               18: arraylength           19: istore_3              20: iconst_0              21: istore        4        23: iload         4        25: iload_3               26: if_icmpge     49        29: aload_2               30: iload         4        32: aaload                33: astore        5        35: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;        38: aload         5        40: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V        43: iinc          4, 1        46: goto          23        49: return              LineNumberTable:        line 7: 0        line 9: 15        line 11: 35        line 9: 43        line 13: 49      StackMapTable: number_of_entries = 2           frame_type = 255 /* full_frame */          offset_delta = 23          locals = [ class "[Ljava/lang/String;", class "[Ljava/lang/String;", class "[Ljava/lang/String;", int, int ]          stack = []           frame_type = 248 /* chop */          offset_delta = 25}
     
    
   
  

?? Why not? It doesn't matter ~ Here we can note that the foreach syntax of the array does not use Iterable for conversion. The above information only involves some content of the Pressure stack outbound. The actual parsing result is as follows:

package foreach;public class ForeachTest2{    public ForeachTest2()    {    }    public static void main(String[] args)    {        int arr[] = {1,2};        int [] arr$ = arr;        for(int len$ = arr$.length, i$ = 0; i$
  

?? We can see that the array is actually converted to a normal traversal;
?? The information about the foreach syntax sugar ends the syntax like this? Apparently not!
?? For a set that implements the RandomAccess interface, such as ArrayList, we should use the most common for loop instead of the foreach loop for traversal. Therefore, there is a defect in the first example.
?? First, let's take a look at the definition of the RandomAccess interface in jdk1.7:

java.util
Interface RandomAccess

All Known Implementing Classes:
ArrayList, AttributeList, CopyOnWriteArrayList, RoleList, RoleUnresolvedList, Stack, Vector

public interface RandomAccess
Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.
The best algorithms for manipulating random access lists (such as ArrayList) can produce quadratic behavior when applied to sequential access lists (such as LinkedList). Generic list algorithms are encouraged to check whether the given list is an instanceof this interface before applying an algorithm that would provide poor performance if it were applied to a sequential access list, and to alter their behavior if necessary to guarantee acceptable performance.
It is recognized that the distinction between random and sequential access is often fuzzy. For example, some List implementations provide asymptotically linear access times if they get huge, but constant access times in practice. Such a List implementation should generally implement this interface. As a rule of thumb, a List implementation should implement this interface if, for typical instances of the class, this loop:
for (int i=0, n=list.size(); i < n; i++)
list.get(i);

runs faster than this loop:
for (Iterator i=list.iterator(); i.hasNext(); )
i.next();

This interface is a member of the Java Collections Framework.
Start:
1.4

?? It doesn't matter if you don't understand English. Let me explain the last rough sentence: actual experience shows that the class instance implementing the RandomAccess interface should be randomly accessed, the efficiency of using a common for loop is higher than that of using a foreach loop. In turn, Iterator is more efficient for sequential access.
?? The following code can be used for judgment:

 if (list instanceof RandomAccess) { for (int i = 0; i < list.size(); i++){} }else { Iterator  iterator = list.iterable(); while (iterator.hasNext()){iterator.next()} }

In fact, if you have read the source code of ArrayList, you can also note that the underlying layer of ArrayList is implemented using arrays. If Iterator traversal is used, you need to create many pointers to execute these values (such as next (); hasNext (), which will inevitably increase the memory overhead and execution efficiency.

??

Appendix: javap (disassembly command) Details
?? Javap is the Built-in anti-assembler of JDK. You can view the bytecode generated by the java compiler. Through it, we can compare the source code and bytecode to learn a lot about the internal work of the compiler.
?? Syntax:
??Javap [Command Options] class...
?? The javap command is used to parse class files. The output depends on the options used. If no option is used, javap will output the public domain and method of the class passed to it. Javap outputs it to the standard output device.
Command Options
-Help outputs help information for javap.
-L output rows and local variable tables.
-B ensures backward compatibility with JDK 1.1 javap.
-Public: Only public classes and members are displayed.
-Protected: only the protected and public classes and members are displayed.
-The package only displays the package, protected, and public classes and members. This is the default setting.
-Private: displays all classes and members.
-J [flag] directly transmits the flag to the runtime system.
-S output internal type signature.
-C: the unparsed code of each method in the output class, that is, the instruction that constitutes the Java bytecode.
-Verbose outputs the stack size, the locals and args numbers of each method, and the compiled version of the class file.
-Classpath [path] specifies the javap used to find the class path. If this option is set, it overwrites the default value or the CLASSPATH environment variable. Directories are separated by colons.
-Bootclasspath [path] specifies the path used to load the UDF class. By default, the UDF class is used to implement the core Java platform and is located in jrelibt. jar and jrelibi18n. jar.
-Extdirs [dirs] overwrites the location where the installation method is extended. The default extension location is jrelibext.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.