Me perguntaram sobre strings imutáveis em Java. Fui encarregado de escrever uma função que concatenou um número de "a" s em uma string.
O que eu escrevi:
public String foo(int n) {
String s = "";
for (int i = 0; i < n; i++) {
s = s + "a"
}
return s;
}
Perguntaram-me quantas seqüências de caracteres esse programa geraria, assumindo que a coleta de lixo não ocorra. Meus pensamentos para n = 3 foram
- ""
- "uma"
- "uma"
- "aa"
- "uma"
- "aaa"
- "uma"
Essencialmente, duas strings são criadas em cada iteração do loop. No entanto, a resposta foi n 2 . Quais seqüências de caracteres serão criadas na memória por essa função e por que é assim?
Respostas:
As strings 1 (
""
) e 2 ("a"
) são as constantes do programa, elas não são criadas como parte das coisas, mas são 'internadas' porque são constantes que o compilador conhece. Leia mais sobre isso em String interning na Wikipedia.Isso também remove as seqüências 5 e 7 da contagem, pois são as mesmas
"a"
que a seqüência 2. Isso deixa as seqüências 3, 4 e 6. A resposta é "3 cadeias são criadas para n = 3" usando seu código.A contagem de n 2 está obviamente errada, porque em n = 3, isso seria 9 e, até mesmo, na sua pior resposta, isso era apenas 7. Se suas seqüências não internadas estavam corretas, a resposta deveria ser 2n + 1.
Então, a questão de como você deve fazer isso?
Como a String é imutável , você deseja algo mutável - algo que pode ser alterado sem criar novos objetos. Esse é o StringBuilder .
A primeira coisa a olhar são os construtores. Nesse caso, sabemos quanto tempo a string será e existe um construtor
StringBuilder(int capacity)
que significa que alocamos exatamente o quanto precisamos.Em seguida,
"a"
não precisa ser uma String , mas pode ser um personagem'a'
. Isso tem um pequeno aumento no desempenho ao chamarappend(String)
vsappend(char)
- com oappend(String)
, o método precisa descobrir quanto tempo a String é e fazer algum trabalho nisso. Por outro lado,char
sempre tem exatamente um caractere.As diferenças de código podem ser vistas em StringBuilder.append (String) vs StringBuilder.append (char) . Não é algo para se preocupar muito , mas se você estiver tentando impressionar o empregador, é melhor usar as melhores práticas possíveis.
Então, como fica isso quando você o reúne?
Um StringBuilder e um String foram criados. Nenhuma string extra precisava ser internada.
Escreva alguns outros programas simples no Eclipse. Instale o pmd e execute-o no código que você escreve. Observe o que se queixa e corrija essas coisas. Teria encontrado a modificação de uma String com + em um loop, e se você a alterasse para StringBuilder, talvez tivesse encontrado a capacidade inicial, mas certamente perceberia a diferença entre
.append("a")
e.append('a')
fonte
Em cada iteração, um novo
String
é criado pelo+
operador e atribuído as
. Após o retorno, todos eles, exceto o último, são coletados no lixo.As constantes de string gostam
""
e"a"
não são criadas sempre, são cadeias internas . Como as cordas são imutáveis, elas podem ser compartilhadas livremente; isso acontece com constantes de string.Para concatenar seqüências de caracteres com eficiência, use
StringBuilder
.fonte
Como MichaelT explica em sua resposta, seu código aloca O (n) strings. Mas também aloca O (n 2 ) bytes de memória e é executado no tempo O (n 2 ).
Aloca O (n 2 ) bytes, porque as seqüências que você está alocando têm comprimentos 0, 1, 2,…, n-1, n, que soma (n 2 + n) / 2 = O (n 2 ).
O tempo também é O (n 2 ), porque a alocação da i-ésima sequência requer a cópia da (i-1) -ésima sequência, que tem o comprimento i-1. Isso significa que cada byte alocado deve ser copiado, o que levará tempo O (n 2 ).
Talvez seja isso que os entrevistadores quiseram dizer?
fonte