Builder mode and StringBuilder source code

Posted by Ziq on Wed, 29 Jan 2020 05:42:13 +0100

Builder pattern

Builder mode is an object creation mode, which is used to create composite objects. When an object is composed of multiple objects, and the combination may change greatly, the construction of sub objects and the combination of sub objects can be encapsulated by using builder mode. Here is an example of fast food assembly.
Driver class: Main.java

public class Main {
    public static void main(String[] args) {
        Meal chickenMeal = MealBuilder.getChickenMeal();
        System.out.println(chickenMeal);        // Meal: Chicken Burger + Coke, Price: 14.0

        Meal beefMeal = MealBuilder.getBeefMeal();
        System.out.println(beefMeal);           // Meal: Beef Burger + Orange Juice, Price: 20.0
    }
}

Staple base class: Burger.java

public abstract class Burger {
    public String getVegetable() {
        return "lettuce";
    }

    public abstract String getMeat();

    public abstract float getPrice();
}

Drink base class: Drink.java

public interface Drink {
    public String getLiquid();

    public float getPrice();
}

Staple food class: ChickenBurger.java

public class ChickenBurger extends Burger {
    @Override
    public String getMeat() {
        return "Chicken";
    }

    @Override
    public float getPrice() {
        return 10.5f;
    }

    @Override
    public String toString() {
        return "Chicken Burger";
    }
}

Main food class: BeefBurger.java

public class BeefBurger extends Burger {
    @Override
    public String getMeat() {
        return "Beef";
    }

    @Override
    public float getPrice() {
        return 15.5f;
    }

    @Override
    public String toString() {
        return "Beef Burger";
    }
}

Beverage: Coke.java

public class Coke implements Drink {
    @Override
    public String getLiquid() {
        return "coke";
    }

    @Override
    public float getPrice() {
        return 3.5f;
    }

    @Override
    public String toString() {
        return "Coke";
    }
}

Beverage: OrangeJuice.java

public class OrangeJuice implements Drink {
    @Override
    public String getLiquid() {
        return "orange";
    }

    @Override
    public float getPrice() {
        return 4.5f;
    }

    @Override
    public String toString() {
        return "Orange Juice";
    }
}

Package class: Meal.java

public class Meal {
    private Burger burger;
    private Drink drink;

    public Burger getBurger() {
        return burger;
    }

    public void setBurger(Burger burger) {
        this.burger = burger;
    }

    public Drink getDrink() {
        return drink;
    }

    public void setDrink(Drink drink) {
        this.drink = drink;
    }

    public float getPrice() {
        return burger.getPrice() + drink.getPrice();
    }

    @Override
    public String toString() {
        return "Meal: " + burger.toString() + " + " + drink.toString() + ", Price: " + getPrice();
    }
}

Package builder class: MealBuilder.java

public class MealBuilder {
    public static Meal getChickenMeal() {
        Meal meal = new Meal();
        meal.setBurger(new ChickenBurger());
        meal.setDrink(new Coke());
        return meal;
    }

    public static Meal getBeefMeal() {
        Meal meal = new Meal();
        meal.setBurger(new BeefBurger());
        meal.setDrink(new OrangeJuice());
        return meal;
    }
}

StringBuilder source code

StringBuilder

Java's StringBuider applies the builder pattern. The following analyzes the StringBuilder source code based on jdk 11.0.4.
The signature of StringBuilder class is as follows. You can see that the base class of StringBuilder is AbstractStringBuilder:

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, Comparable<StringBuilder>, CharSequence

The most important method in StringBuilder is append method, which is equivalent to the builder's object composition method in builder mode. It combines boolean, char, int, long, float, double, String, char[], CharSequence, String, StringBuilder, StringBuffer, Object and other objects into strings needed by programmers.
The most critical and commonly used method is public StringBuilder append(String str). Many other append methods of different types actually refer to the append method of strings. The concrete implementation of this method is in the base class AbstractStringBuilder of StringBuilder.
The @ HotSpot intrinsic candidate annotation indicates that this method has a more efficient optimized implementation based on virtual machine instructions in HotSpot. The Java implementation in Java source code is just the function interpretation. For specific explanation, see appendix.

@Override
@HotSpotIntrinsicCandidate
public StringBuilder append(String str) {
	super.append(str);
	return this;
}

AbstractStringBuilder

The property of AbstractStringBuilder class, mainly a byte sequence value and the last byte position mark count:

/**
* The value is used for character storage.
*/
byte[] value;

/**
* The id of the encoding used to encode the bytes in {@code value}.
*/
byte coder;

/**
* The count is the number of characters used.
*/
int count;

For the append(String) method of the AbstractStringBuilder class, first confirm whether the capacity of the current value will be exceeded after adding the string. If the capacity is exceeded, open a new capacity to value, and then put the string into value by byte:

/**
* Appends the specified string to this character sequence.
* <p>
* The characters of the {@code String} argument are appended, in
* order, increasing the length of this sequence by the length of the
* argument. If {@code str} is {@code null}, then the four
* characters {@code "null"} are appended.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the {@code append} method. Then the character at
* index <i>k</i> in the new character sequence is equal to the character
* at index <i>k</i> in the old character sequence, if <i>k</i> is less
* than <i>n</i>; otherwise, it is equal to the character at index
* <i>k-n</i> in the argument {@code str}.
*
* @param   str   a string.
* @return  a reference to this object.
*/
public AbstractStringBuilder append(String str) {
    if (str == null) {
        return appendNull();
    }
    int len = str.length();
    ensureCapacityInternal(count + len);
    putStringAt(count, str);
    count += len;
    return this;
}

The comparison between StringBuilder and String in splicing efficiency

The value attribute of the String class is final and cannot be changed. Therefore, the + operator is used for String splicing. In fact, the new operation is similar to the new operation, and a new String object is generated.

/**
* The value is used for character storage.
*
* @implNote This field is trusted by the VM, and is a subject to
* constant folding if String instance is constant. Overwriting this
* field after construction will cause problems.
*
* Additionally, it is marked with {@link Stable} to trust the contents
* of the array. No other facility in JDK provides this functionality (yet).
* {@link Stable} is safe here, because value is never null.
*/
@Stable
private final byte[] value;

The value attribute of StringBuilder class has no final keyword modification and can be changed dynamically. Therefore, when it is necessary to splice strings multiple times, StringBuilder can save the overhead of creating string objects multiple times and improve the efficiency.
As for why the value property of String class should be designed to be immutable, it is mainly for the consideration of security, thread security and the implementation of String constant pool.

appendix

  • Interface notes for HotSpotIntrinsicCandidate
The {@code @HotSpotIntrinsicCandidate} annotation is specific to the
 HotSpot Virtual Machine. It indicates that an annotated method
 may be (but is not guaranteed to be) intrinsified by the HotSpot VM. A method
 is intrinsified if the HotSpot VM replaces the annotated method with hand-written
 assembly and/or hand-written compiler IR -- a compiler intrinsic -- to improve
 performance. The {@code @HotSpotIntrinsicCandidate} annotation is internal to the
 Java libraries and is therefore not supposed to have any relevance for application
 code.
694 original articles published, 140 praised, 230000 visitors+
His message board follow

Topics: Java JDK Attribute encoding