How to splice strings gracefully in Java

In Java, how do we do string splicing? String splicing is something we often do in Java code, which is to splice multiple strings together. As we all know, string is an immutable class in Java, so once it is instantiated, it cannot be modified. So how can we gracefully splice our strings? I found a lot of technical data here. Basically, the string splicing in Java is here.
As mentioned above, strings are immutable, so how to splice strings? In fact, the splicing of strings here is to combine two strings into a new string, that is, the last three strings.

How simple it is to use + to splice

This should be the simplest way, but I'm sorry to tell you that Alibaba doesn't recommend using "+" in the for loop for string splicing in their specifications. The "no suggestion" here means that it is not allowed. It's just a euphemism. In fact, there are fewer "+" splices.

I saw an article while visiting the Alibaba developer community Why Alibaba does not recommend using "+" for string splicing in the for loop "+" is not an operator overload, and Java does not support this so-called operator overload. The author proposes that this is a syntactic sugar of Java.

Operator overloading: in computer programming, operator overloading is a kind of polymorphism. Operator overloading is to redefine the existing operators and give them another function to adapt to different data types.

Syntax sugar: syntax sugar, also translated as icing grammar, is a term invented by Peter randing, a British computer scientist. It refers to a kind of grammar added to a computer language, which has no effect on the function of the language, but is more convenient for programmers to use. Syntax sugar makes the program more concise and readable.

concat

This is the method provided in String. The usage is as follows:

        String strA = "Hello" ;
        String strB = "world" ;
        String concat = strA.concat(",").concat(strB);

The internal implementation is to expand the character array to form a new character array buf, and then add the parameter str. Finally, convert the character array to a string.

    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

StringBuffer / StringBuilder

These two should be the twin brothers of one family. The append() method is used for string splicing:

The method of append(String str) in StringBuilder is as follows: in fact, it is almost the same as concat method.

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
    // This is super.append()
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

The method of append(String str) in StringBuffer is as follows:

    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

        public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

We can see that the append method we implemented is the same, the only difference is that StringBuffer is a thread safe splicing. Let's take a look at the inheritance relationship between these two classes.

StringUtils.join

This method is not Java, but Apache. Methods are in apache.commons.

StringUtils.join(strA, ",", strA)

The main function of this method is to combine an array or collection with a certain splicer to form a new string.

String []list  ={"hello","world"};
StringUtils.join(list, ",")

There is also a join method in Java 8:

        String message = String.join("-", "Java", "is", "cool");

        List<String> strings = new LinkedList<>();
        strings.add("Java");
        strings.add("is");
        strings.add("cool");
        String message = String.join(" ", strings);
        //message returned is: "Java is cool"

        Set<String> strings = new LinkedHashSet<>();
        strings.add("Java");
        strings.add("is");
        strings.add("very");
        strings.add("cool");
        String message = String.join("-", strings);
        //message returned is: "Java-is-very-cool"

StringJoiner: a new skill in Java 8

Just mentioned that there are join methods in Java 8. I'll check the first join method and find a new class. Let's take a look at the new class StringJoiner.java

    public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }

When StringJoiner(CharSequence delimiter) initializes a StringJoiner, the delimiter is actually a separator, not the initial value of a variable string.

We see the joiner.add(cs), and then we make a joiner.toString(). Is it very similar to the append method in our StringBuilder? Let's go in and see this method.

    public StringJoiner add(CharSequence newElement) {
        prepareBuilder().append(newElement);
        return this;
    }

Is it similar to StringBuilder now? Let's see what prepareBuilder() is

    private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);
        }
        return value;
    }

We have seen that he is actually a StringBuilder. Then his performance should be comparable to our StringBuilder.

This StringJoiner was introduced in Java 8, which is not just for no reason. In Java, we see many new elements, such as Stream

for instance:

There is now a collection:

List<String> list = ImmutableList.of("Java" , "is" , "the" , "best" , "language");

Now, the form I need is this:

Java is the best language

+

If you want to use +, you have to traverse. It must be a loop plus "+", and then we will pass directly.

concat

        String str = "" ;
        for (int i = 0; i < list.size(); i++) {
            str = str.concat(" ").concat(list.get(i)) ;
        }

StringBuilder

        StringBuilder sb = new StringBuilder() ;
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i)).append(" ") ;
        }

It can also be written as follows:

String result = list.stream().reduce(new StringBuilder(), (sb, str) -> sb.append(str).append(" "), StringBuilder::append).get();

Of course, if you don't want to use StringBuilder here, you can change it to +. It looks simple

String result = list.stream().reduce((a,b)->a+" "+b).get();

StringJoiner

The above methods are very common and simple. Now let's see how to use them:

String result = list.stream().collect(Collectors.joining(" "));

That's it. The implementation here is as follows:

    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
        return joining(delimiter, "", "");
    }

        public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                                             CharSequence prefix,
                                                             CharSequence suffix) {
        return new CollectorImpl<>(
                () -> new StringJoiner(delimiter, prefix, suffix),
                StringJoiner::add, StringJoiner::merge,
                StringJoiner::toString, CH_NOID);
    }

summary

Now the problem is coming. All the above methods are easy to use. How to choose?

  • What doesn't involve circulation is the simple splicing, which is simple and convenient;
  • When it comes to loops, such as for, you can consider using StringBuilder. If you need thread safety, you can choose StringBuffer;
  • With List, StringJoiner is a good choice.
  • concat depends on your mood. If you don't want to use + then use it.

In fact, I have used these two in string quota splicing, which should be more frequently used:

  • String java = String.format("%s is the beat language", "Java");
  • MessageFormat.format("{0} is the beat language" , "Java") ;

The MessageFormat method is in java.text, so it is more friendly to some text class data (string). When I used to use this method, I had a number of 20 million, which was converted to 20 million by this class. String.format() is not a problem. It depends on your choice. In fact, these two methods can not be called string splicing. At most, they are string formatting. The format method means format quota.

Tags: Java Apache Programming

Posted on Sun, 02 Feb 2020 04:11:34 -0800 by sleepingdanny