Por que o Alibaba não recomenda o uso de "+" para emenda de cordas em um loop for

Este artigo também é um suplemento ao conhecimento de strings em Java, principalmente para apresentar o conhecimento de emenda de strings. Este artigo é baseado em jdk1.8.0_181.

1. A forma de emenda da corda

1. União de cordas

A emenda de strings é algo que costumamos fazer no código Java, que consiste em unir várias strings.

Todos nós sabemos que String é uma classe imutável em Java , portanto, uma vez instanciada, não pode ser modificada.

Depois que uma instância de uma classe imutável é criada, o valor de suas variáveis ​​de membro não pode ser modificado. Este projeto tem muitas vantagens, como a capacidade de armazenar em cache o código hash, uso mais conveniente e mais seguro.

No entanto, como as strings são imutáveis, o que dizer da concatenação de strings?

Imutabilidade da corda e emenda da corda

Na verdade, toda a chamada emenda de strings regenera uma nova string. O seguinte código de emenda de string:

String s = "abcd";
s = s.concat("ef");

 Na verdade, o s que obtemos no final já é uma nova string. Como mostrado abaixo

Salvo em s é uma referência a um objeto String recém-criado.

Então, em Java, como concatenar strings? Existem muitas maneiras de concatenar strings, aqui estão algumas das mais comumente usadas.

2. Use +cordas de emenda

Em Java, a maneira mais fácil de concatenar strings é usar símbolos diretamente +para concatenar. Tal como:

String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
String hollis = wechat + "," + introduce;

Aqui está um ponto especial: algumas pessoas +entendem a função de concatenar strings em Java como sobrecarga de operador . Na verdade, não, o Java não suporta sobrecarga de operador . Na verdade, isso é apenas um açúcar sintático fornecido pelo Java . Os detalhes serão descritos posteriormente.

Sobrecarga do operador: Na programação de computador, a sobrecarga do operador (inglês: sobrecarga do operador) é um tipo de polimorfismo. A sobrecarga do operador consiste em redefinir os operadores existentes e dar-lhes outra função para se adaptar a diferentes tipos de dados.

Açúcar sintático: o açúcar sintático, também traduzido como gramática revestida de açúcar, é um termo inventado pelo cientista da computação britânico Peter Landing. Refere-se a uma determinada gramática adicionada a uma linguagem de computador. Essa gramática não tem efeito sobre a função da linguagem. Mas é mais conveniente para os programadores usarem. O açúcar sintático torna o programa mais conciso e legível.

3 、 concat

 Além de usar +strings concatenadas, você também pode usar o método concat na classe String para concatenar strings. Tal como:

String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
String hollis = wechat.concat(",").concat(introduce);

4 、 StringBuilder + StringBuffer

Na string, Java define, além de ser usado para definir uma constante de string na Stringclasse, também pode ser fornecida para definir uma variável de string na StringBufferclasse, pode ser estendida e o objeto é modificado.

Ele StringBufferpode ser usado para concatenar strings facilmente. Tal como:

StringBuffer wechat = new StringBuffer("Hollis");
String introduce = "每日更新Java相关技术文章";
StringBuffer hollis = wechat.append(",").append(introduce);

5 、 StringUtils.join

Além do método de splicing de string integrado no JDK, você também pode usar os nomes dos métodos de splicing de string fornecidos em algumas bibliotecas de software livre, como as classes apache.commons中fornecidas StringUtils, onde os joinmétodos podem unir strings.

String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
System.out.println(StringUtils.join(wechat, ",", introduce));

 Aqui está uma breve introdução, a principal função do método de junção fornecido em StringUtils é: splicing arrays ou coleções junto com um determinado caractere de splicing para formar uma nova string, como:

String []list  ={"Hollis","每日更新Java相关技术文章"};
String result= StringUtils.join(list,",");
System.out.println(result);
//结果:Hollis,每日更新Java相关技术文章

Além disso, a classe String em Java 8 também fornece um método de junção estática, o uso é semelhante a StringUtils.join.

Acima estão os cinco métodos mais comumente usados ​​para concatenar strings em Java, então qual é o melhor? Por que não é recomendado o uso de +emenda de strings no corpo do loop no Manual de Desenvolvimento do Alibaba Java ?

Ainda é um pedaço de código. Vamos descompilar o bytecode gerado por ele e ver o resultado.

String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
String hollis = wechat + "," + introduce;

O conteúdo após a descompilação é o seguinte, a ferramenta de descompilação é jad.

String wechat = "Hollis";
String introduce = "\u6BCF\u65E5\u66F4\u65B0Java\u76F8\u5173\u6280\u672F\u6587\u7AE0";//每日更新Java相关技术文章
String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();

Observando o código descompilado, podemos descobrir que a constante da string original é processada por seu método append depois de converter a String em StringBuilder durante o processo de emenda.

Em outras palavras, +o princípio de realização da concatenação de strings em Java é usar StringBuilder.append.

2. Princípios

1 、 concat

Vamos dar uma olhada no código-fonte do método concat e ver como esse método é implementado.

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);
}

Este código primeiro cria uma matriz de caracteres cujo comprimento é a soma do comprimento da string existente e da string a ser emendada, em seguida, copia os valores das duas strings para a nova matriz de caracteres e usa esta matriz de caracteres para criar um novo O objeto String e o retorno.

Por meio do código-fonte, também podemos ver que, após o método concat, uma nova String é realmente nova, o que reflete a imutabilidade das strings mencionadas anteriormente.

2 、 StringBuffer + StringBuilder

Em seguida, examinamos StringBuffere StringBuilderimplementamos os princípios.

E Stringclasse Da mesma forma, a StringBuilderclasse também encapsula uma matriz de caracteres é definida da seguinte maneira:

char[] value;

A Stringdiferença é que não é final, por isso pode ser modificado. Além disso, Stringao contrário, nem todas as posições na matriz de caracteres foram usadas. Ela tem uma variável de instância que indica o número de caracteres usados ​​na matriz, que é definido da seguinte maneira:

int count;

O código-fonte anexado é o seguinte:

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

Esta classe herda a AbstractStringBuilderclasse, observe seus appendmétodos:

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;
}

append copiará diretamente os caracteres para a matriz de caracteres interna; se o comprimento da matriz de caracteres não for suficiente, ela se expandirá.

StringBufferE StringBuildersimilarmente, a maior diferença é que ele StringBufferé seguro para thread, olhe para StringBuffero appendmétodo.

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

Este método é usado synchronizedpara declarar que é um método thread-safe. Não StringBuilderé seguro para threads.

3. Princípios de StringUtils.join

Observando StringUtils.joino código-fonte, podemos descobrir que, de fato, ele também é obtido por meio de StringBuilder.

public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
    if (array == null) {
        return null;
    }
    if (separator == null) {
        separator = EMPTY;
    }

    // endIndex - startIndex > 0:   Len = NofStrings *(len(firstString) + len(separator))
    //           (Assuming that all Strings are roughly equally long)
    final int noOfItems = endIndex - startIndex;
    if (noOfItems <= 0) {
        return EMPTY;
    }

    final StringBuilder buf = new StringBuilder(noOfItems * 16);

    for (int i = startIndex; i < endIndex; i++) {
        if (i > startIndex) {
            buf.append(separator);
        }
        if (array[i] != null) {
            buf.append(array[i]);
        }
    }
    return buf.toString();
}

3. Comparação de eficiência

Uma vez que existem tantas maneiras de concatenar strings, qual é a mais eficiente? Vamos comparar brevemente.

long t1 = System.currentTimeMillis();
//这里是初始字符串定义
for (int i = 0; i < 50000; i++) {
    //这里是字符串拼接代码
}
long t2 = System.currentTimeMillis();
System.out.println("cost:" + (t2 - t1));

Usamos o código no formulário acima para testar o tempo de execução dos próximos cinco códigos de emenda de strings. Os resultados são os seguintes:

+ cost:5119
StringBuilder cost:3
StringBuffer cost:4
concat cost:3623
StringUtils.join cost:25726

Pode-se ver a partir dos resultados que a comparação do tempo de curto para longo é:

StringBuilder< StringBuffer< concat< +<StringUtils.join

StringBufferCom StringBuilderbase no processo de sincronização, levará mais tempo.

StringUtils.join também usa StringBuilder e ainda existem muitas outras operações, por isso leva muito tempo e é fácil de entender. Na verdade, StringUtils.join é melhor no processamento de matrizes ou listas de strings.

Então aí vem o problema. Já analisamos antes. Na verdade +, o princípio de implementação do uso de cordas emendadas também é usado. StringBuilderPor que a diferença é tanto, quanto 1000 vezes?

Vamos descompilar o seguinte código:

long t1 = System.currentTimeMillis();
String str = "hollis";
for (int i = 0; i < 50000; i++) {
    String s = String.valueOf(i);
    str += s;
}
long t2 = System.currentTimeMillis();
System.out.println("+ cost:" + (t2 - t1));

O código após a descompilação é o seguinte:

long t1 = System.currentTimeMillis();
String str = "hollis";
for(int i = 0; i < 50000; i++)
{
    String s = String.valueOf(i);
    str = (new StringBuilder()).append(str).append(s).toString();
}

long t2 = System.currentTimeMillis();
System.out.println((new StringBuilder()).append("+ cost:").append(t2 - t1).toString());

Podemos ver que o código descompilado foré newum a cada vez no loop StringBuilder, e então é Stringconvertido StringBuildere executado append.

A criação frequente de novos objetos certamente leva muito tempo, não apenas a criação frequente e demorada de objetos também causará um desperdício de recursos de memória.

Portanto, o Alibaba Java Development Manual recomenda: o corpo do loop, o método de conexão da string e  StringBuilder o  append método usado para expandir. Não use isso +.

Quatro, resumo

Este artigo apresenta o que é emenda de string. Embora a string seja imutável, ela ainda pode ser emendada criando uma nova string.

Existem cinco métodos de emenda de cordas comumente usados, a saber: use +, use concat, use StringBuilder, use StringBuffere use StringUtils.join.

Uma vez que novos objetos são criados durante o processo de emenda da corda, se a emenda da corda for executada em um corpo em loop, questões de memória e eficiência devem ser consideradas.

Portanto, após comparação, constatamos que o StringBuildermétodo de uso direto é o mais eficiente. Porque StringBuilderé projetado para definir strings variáveis ​​e operações de mudança de string.

No entanto, deve ser enfatizado que:

1. Se a corda não estiver emendada no corpo do laço, use +-a diretamente .

2. Se a emenda de cordas for realizada em uma cena simultânea, use StringBuffer-a StringBuilder.

 

Anterior: Resumo do conhecimento básico de Java (absolutamente clássico)

Próximo: Resumo das perguntas da entrevista em Java (com respostas)

 

 

 

 

 

 

 

 

Acho que você gosta

Origin blog.csdn.net/guorui_java/article/details/109759292
Recomendado
Clasificación