When we use the separator to concatenate strings, we use StringBuffer or StringBuilder class to write string concatenation methods. Every time the concatenated object is converted into a string, we need to remove the last separator. Or determine whether to add a separator for the first concatenation. We added a StringJoiner class after JDK8, so we don’t have to go through the trouble of concatenating strings, we just use this class.

1. The StringJoiner class is basically used

We can construct sequences of characters separated by delimiters, optionally beginning with the provided prefix and ending with the provided suffix. Then call the add method to add the string. Example code is as follows:

StringJoiner StringJoiner = new StringJoiner(","."<".">"); // Add null string stringJoiner.add(null); stringJoiner.add("1111");
      System.out.println(stringJoiner.toString());

      StringJoiner stringJoiner2 = new StringJoiner("|"."(".")"); // Add null string stringJoiner2.add("aaaa");
      stringJoiner2.add("bbbb"); System.out.println(stringJoiner.merge(stringJoiner2)); The results are as follows: < null, 1111 > < null, 1111, aaaa | BBBB >Copy the code

This class is also used in the JDK8 stream, with the following code:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String commaSeparatedNumbers = numbers.stream()
         .map(i -> i.toString())
        .collect(Collectors.joining(","));
Copy the code

 

2. StringJoiner parses the source code

(1) What is the return value of toString() when no element is added?

By default, the prefix + suffix string or value attribute returned by toString() when no element has been added, that is, value has not been initialized. When we haven’t actually added any elements, the property returned is emptyValue, a string of prefix + suffix. When we add an element, the return attribute is value. The two types are different. EmptyValue is a String and value is a StringBuilder. The source code is as follows:

//StringBuilder value - At any time, characters are made up of prefixes, the added elements are delimited by delimiters, // but there is no suffix, so we can add elements more easily without having to shake the suffix every time. private StringBuilder value; // The prefix + suffix string or value attribute returned by toString () by default when no element has been added (that is, if empty). The user might overwrite it with other values, including an empty String. private String emptyValue;Copy the code

Note: The value attribute is made of prefixes and added elements are delimited by delimiters, but there are no suffixes, so we can add elements more easily without having to shake the suffix every time.

ToString () :

// Add the element as empty, return the suffix concatenation String @override public StringtoString() {// Add element empty, return suffix concatenation stringif (value == null) {
          return emptyValue;
      } else{// Determine whether the suffix is emptyif (suffix.equals("")) {
              return value.toString();
          } else{ int initialLength = value.length(); String result = value.append(suffix).toString(); // reset value to pre-append initialLength // Reset value to pre-append initialLength to continue with value.setLength(initialLength);returnresult; }}}Copy the code

(2) How to add elements when the element of add is null?

If the argument is null, it does not null check, it adds the null as a string.

StringJoiner add method:

/** * note: * 1. The argument type is CharSequence interface, String, StringBuilder, StringBuffer, etc. * inherits this interface * 2. When the argument is passed as null, it does not null check, */ public StringJoiner add(CharSequence newElement) {prepareBuilder().append(newElement);return this;
    }
Copy the code

Note: The parameter type of the Add method is the CharSequence interface, which is inherited by String, StringBuilder, StringBuffer, and so on.

AbstractStringBuilder < AbstractStringBuilder > < AbstractStringBuilder >

Override public AbstractStringBuilder appEnd (CharSequence s) {// add a null string when s is nullif (s == null)
            returnappendNull(); // Stringif (s instanceof String)
            returnthis.append((String)s); // AbstractStringBuilder subclasses abstractBuffer and StringBuilderif (s instanceof AbstractStringBuilder)
            returnthis.append((AbstractStringBuilder)s); // Inherit the CharSequence interface, in addition to the above type of operationsreturn this.append(s, 0, s.length());
    }
Copy the code

The StringJoiner class is pretty much the same in terms of using it and parsing the source code. It’s not that complicated, so we’re going to expand a little bit.

 

Knowledge development:


(1) Array. copyOf method is shallow copy, why shallow copy is needed here?

If the access is the reference of the object, the property value of the original object will change. If the deep copy is the copy of the property value instead of the reference of the object, the property of an object in the array will not change. Java has a lot of low-level calls to copy, which is why Java copy is a shallow copy. For example:

      Department[] dept = new Department[2];
      dept[0] = d1;
      Department[] departments = Arrays.copyOf(dept, dept.length);
      System.out.println("======== before change =========");
      System.out.println(dept[0].getId());
      System.out.println(departments[0].getId());
      
      System.out.println("======== after change ========="); d1.setId(2); System.out.println(dept[0].getId()); System.out.println(departments[0].getId()); Here the shallow copy and the deep copy are different.Copy the code

 

EnsureCapacityInternal ()

Private void ensureCapacityInternal(int minimumCapacity) {// Overflow -conscious codeif(minimumCapacity - value.length > 0) {// minimumCapacity is positive, // newCapacity() value = array.copyof (value, newCapacity(minimumCapacity)); }}Copy the code

 

  1. NewCapacity (minimumCapacity) is called in the ensureCapacityInternal() method. If the value of newCapacity is greater than the value of the passed parameter, proceed with the next step. If the value of minCapacity is not greater than the value of the passed parameter, assign the value of minCapacity to newCapacity. (2) Check whether newCapacity is less than or equal to 0 or greater than MAX_ARRAY_SIZE. If newCapacity is larger than MAX_ARRAY_SIZE, the capacity is huge. Otherwise, newCapacity is the size of newCapacity.
/** * returns a capacity that is at least equal to the given minimum capacity. If sufficient, the current capacity increased by the same amount + 2 is returned. * No capacity greater than {@code MAX_ARRAY_SIZE} is returned unless the given minimum capacity is greater than that. */ private int newCapacity(int minCapacity) {// overflow-conscious code int newCapacity = (value.length << 1) + 2; // When the capacity is smaller than the parameter sentif(newCapacity -mincapacity < 0) {// Set newCapacity = minCapacity; }return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }
Copy the code

 

(1) why MAX_ARRAY_SIZE = integer.max_value – 8?

Arrays are a special type in Java; they are neither primitive data types (kidding, of course not) nor reference data types. Unlike ordinary “instance of class” objects, arrays in Java are not classes, so there are no corresponding class files. Array types are synthesized by the JVM from element types. Getting the length of an array in the JVM is done using a special bytecode instruction called ArrayLength; There is a _length field in the object head of the array, which records the length of the array. Just read the _length field. So the maximum length defined in the ArrayList is Integer minus 8, which is the value of the _length field.

The original link: blog.csdn.net/alexdedream… For details about the object header, see www.2cto.com/kf/201603/4… This blog post

The source code is as follows:

/** * The maximum size of the array to allocate (unless necessary). Some virtual machines keep some header information in arrays. * Attempting to allocate a larger array may cause OutOfMemoryError: The requested array size exceeds the VM limit */ private static final Int MAX_ARRAY_SIZE = integer.max_value - 8;Copy the code

 

In order to facilitate those who like to study can read technical articles anytime and anywhere, I created a public account, the subsequent articles will be updated in time on the public account, the following is my public account, readers can pay attention to: