StringBuffer in Dart
Tags: dart, flutter, opensource
Published: 2021-09-28 04:27:35

Imagine you are building the next Billion Dollar app 💵 that has a lot of innovative features which are new to the tech world. But your app crashes a lot! Further investigation proved that the code you wrote for the app is not optimized.
Uff ! Thats a bummer 😐.  What would you do?

Well, you call me 📲 ! 
Nahh, just open this tutorial.✅

Most of the apps out there incorporate **String Concatenation** in some or the other way. It could be to join the First Name and Last Name of a person, or get the list of cities the user has travelled this year, and the list goes on.

Most of the developers including me, follow one approach for string concatenation, ie, using the '+' operator.
Here is a basic example to illustrate what i meant:

```dart
String? firstName = "Aswin";
String? lastName = "Gopinathan";

String? fullName = firstName + " " + lastName;
```

This is the most typical approach, and it's easier too. But this approach comes with a price.

And the price is memory !!

Let's see another example where we concatenate strings from a List:

```dart
List<String> cities = ["Bangalore","Mumbai","Delhi","Chennai"];
  
String finalCities = "";
  
for(String city in cities) {
  finalCities += (city+' ');
}
  
print(finalCities);
```

The output will be:

```
Bangalore Mumbai Delhi Chennai 
```

You might have read that Strings in dart are immutable. But, we just updated `finalCities` multiple times. How is it even possible?

Well, the answer to this magic is that every time we concatenate a new string, the compiler allocates a new memory for the resultant string, and the garbage collector is called to de-allocate the previous memory location.

So literally the garbage collector is called for every item you concatenate, and for each of those iterations a new memory location is assigned !!

**Finding it hard to believe?** Its okay, i understand. 

Let's do one thing. Write this line of code inside the for loop from the previous code snippet:

```dart
print(identityHashCode(finalCities));
```
This line of code prints the hashcode of the memory address of the variable `finalCities`.

What do you see? The output should be like this:
```
260230835
327507326
116916136
283166850
```
The values may differ for you.

So, it is pretty clear from this that the variable `finalCities` uses different memory location in every iteration.

But dont worry, if i bummed you out with this, i will fix it too !!

Enter : **StringBuffer** 🥁🥁

**Me** : "Welcome StringBuffer to this article"
**StringBuffer** : "Ahoy ! Let me introduce myself. My name is StringBuffer. I take care of the mess that my ancestor String creates. You know he is pretty old-school.
**Me** : "I know but he is still one of the best. So without any further delays, let me tell everyone how you work."

So, as the official dart docs says :
*"A class for concatenating strings efficiently. Allows for the incremental building of a string using write() methods. The strings are concatenated to a single string only when toString is called."*

Let me break that down for you.

`StringBuffer` is a class that lets you concatenate string efficiently. Duh! you just read that above.
Well, how it works is you use the inbuilt method `write()` to concatenate strings instead of the `+` operator. But what happens with `StringBuffer` is that, it stores the string in a buffer and not in a memory location. It uses the memory only when the `toString()` method is called to create a `String` object.

Tada! Now you don't have to worry about the memory being allocated every time you concatenate.

See, StringBuffer is a superhero 😎

Well, thats all for the theory part 😉
But don't go yet, let's get our hands dirty. Shall we? 😋

So, lets open a new dart file and start off with the main():
```dart
void main() {
  // Enter code here
}
```

Let's create a `StringBuffer` object first. We will be using the same List as before:

```dart
StringBuffer sb = StringBuffer();

List<String> cities = ["Bangalore","Mumbai","Delhi","Chennai"];
```

Now, rewrite the for loop as follows:

```dart
for(String city in cities) {
  sb.write(city+" ");
  // print(identityHashCode(sb));
}
```

We use the `write()` to append new strings to the end. You can uncomment the `print()` statement to confirm no new memory location is created for every concatenation.

Well, now print the result:

```dart
String cityList = sb.toString();
print(cityList);
```
It is at this point a memory location is created to print the concatenated string.

Wow! Thats really great. Now you have reduced one of the many causes of memory leaks in your app 👏👏.
Now, you are one step closer to releasing that Billion-dollar app.

So, with that i am ending this article. But this is not the actual end. I am still exploring Flutter and Dart and as i learn anything new, i will be back with more articles.

So till then, Bye bye !!! 👋