Guava ImmutableMap Builder syntax

23,932

No, they are identical. The reason for the first syntax is that it makes a nice one-liner.

The reason for the second syntax is the you might have a loop or other flow control, you may need to pass the Builder around.

For example:

public static void main(final String[] args) throws Exception {
    final ImmutableList.Builder<Integer> lb = ImmutableList.builder();
    for (final String arg : args) {
        lb.add(Integer.parseInt(arg));
    }
}

And before you say it, yes a FluentIterable would probably be better in this case - but it's just an example.

Share:
23,932

Related videos on Youtube

Durandal
Author by

Durandal

Full Stack engineer and Data Consultant. I work mostly in Java, Groovy, Kotlin, &amp; Python; occasionally in PHP &amp; Ruby. I spend a fair amount of time using R as well to facilitate my data science work. Open Source advocate. I dig data viz stuff as well.

Updated on July 09, 2022

Comments

  • Durandal
    Durandal almost 2 years

    I've been using Guava's ImmutableMap with a Builder for awhile without giving much thought to how/why it works. I've been using the builder in the way described by the Javadoc:

    ImmutableMap<String, Integer> WORD_TO_INT =
              new ImmutableMap.Builder<String, Integer>()
                  .put("one", 1)
                  .put("two", 2)
                  .put("three", 3)
                  .build();
    

    I've also seen examples elsewhere on SO of this syntax:

    ImmutableMap<String,Integer> myMap = ImmutableMap.<String, Integer>builder()
        .put("one", 1) 
        .put("two", 2) 
        .put("three", 3) 
        .build();
    

    Both seem to produce the exact same result.

    A quick glance at the ImmutableMap source shows that the static builder() call in the 2nd example returns: new Builder<K, V>()

    There doesn't appear to be any functional difference between the two methods.

    Is there any difference under the hood? Any reason to prefer one or the other?

    EDIT: Adding bytecode difference.

    The bytecode generated is almost identical except for one line:

    Method 1(Builder<K,V>):

    static {};
         0  new com.google.common.collect.ImmutableMap$Builder [12]
         3  dup
         4  invokespecial com.google.common.collect.ImmutableMap$Builder() [14]
         7  ldc <String "key1"> [17]
         ........
    

    Method 2:(<K,V>builder())

    static {};
         0  invokestatic com.google.common.collect.ImmutableMap.builder() : com.google.common.collect.ImmutableMap$Builder [12]
         3  ldc <String "key1"> [18]
         ........
    

    After that they're pretty much the same, the first line being different makes sense given the source differences, but I'm not sure why the first one calls dup and the second doesn't.

  • Durandal
    Durandal over 10 years
    Any idea why the dup shows up in the bytecode for the first one? I don't know enough about bytecode to know if that's typical or not.
  • Boris the Spider
    Boris the Spider over 10 years
    @MagicMan if you look at the source code you will see that the methods are different - I'm not surprised that the bytecode is different. As to why it duplicates the value, I'm not sure.
  • Durandal
    Durandal over 10 years
    Ahh, as long as there isn't any big difference I won't worry. Example makes it clear how I should be using it, thanks!
  • Vladimir Matveev
    Vladimir Matveev over 10 years
    @MagicMan, you didn't provide full bytecode listing, but I believe that there is something like invokespecial ...ImmutableMap$Builder.<init>() after dup in the first example. This is exactly why dup is needed. In Java construction is two-phase process: first, new memory is allocated via new, and then a constructor method (<init>) is called on that memory. So duped stack element is consumed by the constructor.
  • Durandal
    Durandal over 10 years
    @VladimirMatveev Ahh, sorry, just edited and added that next line. You are correct, it was indeed invokespecial....