DEV Community

Cover image for Melhorando a performance em Kotlin com concatenação de strings
Gabriel Menezes da Silva
Gabriel Menezes da Silva

Posted on

Melhorando a performance em Kotlin com concatenação de strings

Contexto

Trabalhei em um aplicativo mobile nativo para Android utilizado por uma empresa de logística. Esse app é usado por operadores para escanear etiquetas de pacotes e contêineres, a fim de realizar as etapas necessárias no sistema para classificá-los e ordená-los.

Existe uma função responsável por receber a string, manipulá-las e enviar para o back-end a string correta para que ela seja processada.

Essa função é o coração de todo o aplicativo — sem ela, o processo logístico não funcionaria. Portanto, qualquer melhoria nela é sempre muito bem-vinda.

Neste artigo, será explicado quais melhorias foram feitas e os motivos por trás da implementação.

Qual foi a melhoria feita?

Uma operação executada inúmeras vezes dentro dessa função é a concatenação de strings.

Você pode estar se perguntando: por que melhorar a concatenação é importante?

Dependendo de como ela é feita, você literalmente pode ter problemas de desempenho e uso excessivo de memória para obter o resultado final.

O problema

Antes da melhoria, a concatenação das strings era feita da seguinte forma, usando o famoso operador +=, muito comum no dia a dia dos programadores Kotlin:

var result = ""
val iterations = 1000
for (i in 0 until iterations) {
    result += "Item $i "
}
Enter fullscreen mode Exit fullscreen mode

Ok, mas qual é o problema de usar o +=?

  • A classe String é imutável, ou seja, a cada iteração uma nova instância de String é criada, e mais memória é alocada.

Em outras palavras, quanto maior o número de iterações, mais memória é usada e mais tempo é necessário para obter o resultado final!

A solução

Usar o StringBuilder em vez do operador +=.

Os motivos são simples:

  • 1. StringBuilder é mutável, ou seja, nenhuma nova instância de string é criada a cada iteração.
  • 2. A mesma alocação de memória é usada durante todo o processo de concatenação.

O código ficaria da seguinte forma:

val result = buildString {
    for (i in 0 until iterations) {
        append("Item $i ")
    }
}
Enter fullscreen mode Exit fullscreen mode

A função buildString utiliza internamente o StringBuilder.
Para referência, veja a documentação oficial do Kotlin.

Exemplo prático

import kotlin.system.measureTimeMillis

fun main() {
    val iterations = 1000

    // Usando +=
    val timePlusEqual = measureTimeMillis {
        var result = ""
        for (i in 0 until iterations) {
            result += "Item $i "
        }
    }

    // Usando buildString (internamente usa StringBuilder)
    val timeBuildString = measureTimeMillis {
        val result = buildString {
            for (i in 0 until iterations) {
                append("Item $i ")
            }
        }
    }

    println("Tempo com +=: ${timePlusEqual}ms")
    println("Tempo com buildString: ${timeBuildString}ms")
}
Enter fullscreen mode Exit fullscreen mode

E o resultado será uma grande diferença:

Tempo com +=: 21ms

Tempo com buildString: 0ms

Neste artigo foi mostrado apenas um exemplo simples, mas imagine isso em larga escala, com strings enormes — o tempo de execução e o consumo de memória aumentariam consideravelmente.

Conclusão

Muitas vezes pensamos que, para causar um grande impacto em um projeto, é preciso fazer algo gigantesco — como mudar toda a arquitetura do aplicativo.

Mas isso não é verdade.
Pequenas melhorias podem gerar um impacto enorme e entregar valor real aos clientes.
Ter isso em mente traz uma sensação de conforto: saber que otimizações simples também fazem a diferença.

Top comments (0)