.NET, Boas Práticas, Técnicas

String VS StringBuilder – O Coiote não pega o Papa Léguas!

O título desse post remete a dois personagens bem conhecidos de todos (principalmente das crianças) em que um deles sempre tenta capturar o outro, porém esse último é muito mais veloz e raramente se dá mal. A ideia por trás dessa analogia é que algumas vezes tentamos utilizar tipos de dados com limitações de desempenho em nossos códigos e então saímos fazendo mil coisas (“gambiarras”) para tentar se aproximar do melhor desempenho possível, nem preciso comentar o resultado final. Esse fato no leva ao problema de atualização de conhecimento, pesquisas, estudos sobre as novidades de uma linguagem e/ou uma ferramenta. Aquela famosa frase “Para quem só conhece o martelo como ferramenta, parafuso é prego” cabe perfeitamente aqui.
Quando precisamos trabalhar com strings, o primeiro tipo que vem a mente é o tipo String ou string (essa última é apenas um apelido). Legal, esse é o tipo mais conhecido, e naturalmente, mais usado. Acontece que um objeto do tipo String é imutável, o que isso significa? Significa que uma vez atribuído um valor a um objeto desse tipo, esse valor jamais mudará, isso mesmo, jamais mudará. Mas então como eu consigo fazer concatenações e o novo valor é atribuído ao objeto? O que ocorre por baixo dos panos é algo que talvez você nunca imaginasse, a cada nova atribuição de valor a um objeto String, é criado um novo objeto semelhante que agora contém o valor antigo mais o valor atual. Isso mesmo, um novo objeto é criado e isso é transparente aos desenvolvedores. Você simplesmente solicita o valor do objeto e lá está ele.
No momento em que um novo objeto é criado, o objeto antigo continua na memória heap a disposição do garbage collector. A figura 1 mostra esse cenário, podemos ver que ao final das concatenações sucessivas temos um único objeto que iremos trabalhar e mais quatro objetos aguardando para serem eliminados da memória.

StringVSStringBuilderFigura 1

A cada nova iteração criamos um novo objeto e descartamos o antigo, isso causa um overhead imenso nas aplicações e um péssimo aproveitamento da memória do computador. Ma então o que devemos fazer quando precisarmos utilizar strings em iterações? A solução presente no .NET chama-se StringBuilder. Essa classe foi especialmente desenhada para trabalhar com strings dinâmicas, strings em que o valor muda constantemente e garante uma performance excelente quando recebe grande quantidade de dados. Os métodos disponíveis para trabalhar com StringBuilder fazem uma referência a mesma instância e não a uma nova como no caso da String. Vamos ver na prática como isso funciona. A figura 2 mostra dois métodos, o primeiro faz um loop de 20000 iterações utilizando um objeto StringBuilder e ao final exibe em milissegundos o tempo gasto. O segundo método faz a mesma coisa porém utilizando um objeto String.

ExemploCodigo

Figura 2

ExemploStringBuilder_2

Figura 3

Ao compararmos os resultados da figura 3, podemos concluir a enorme diferença no tempo de execução. Quando chamamos o método que utiliza String, gastamos um tempo de 2637 milissegundos e o mesmo loop utilizando StringBuilder consumiu apenas 10 milissegundos.
Então o tipo de dados String é um tipo ruim de trabalhar? A resposta é que String não é um tipo de dados ruim para trabalhar, porém ela atende exatamente aquilo que ela se propôs a atender, trabalhar com strings estáticas ou com poucas mudanças.

Abraços!

Padrão