Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding memory inefficiency when overring toString() of a common POJO using StringBuilder

I'm developing a project that all my POJOs must have they toString() inherited from Object class overridden.

Consider the immutable class below:

public final class SomeActivity {
    private final int id;
    private final String name;
    private final String description;
    private final DateTime startDate;
    private final DateTime endDate;
    private final String note;

    // Constructors and getters

    // My future implementation of toString
}

My objective when overriding toString() is to achieve and output similar of the output below (using test values of all SomeActivity class fields):

[Id: 1, Name: Read a book, Description: Trying to discover how to build a plane, StartDate: 17/10/2013, EndDate: 15/11/2013, Note: I really need this]

So, I have two solutions in mind:

1 - Concatenate Strings

As far I know, String is a immutable class. (refer to the javadoc), so, if I implement a method to receive such output, I may have many objects being created because of my concatenations:

@Override
public String toString() {
    String s = "[Id: " + id + 
            ", Name: " + name + 
            ", Description: " + description + 
            ", StartDate: " + startDate + 
            ", EndDate: " + endDate + 
            ", Note: " + note + 
            "]";
}

2 - Using StringBuilder

With StringBuilder approach, in theory, I would have less objects being instantiated instead of the "concatenation approach". But notice new StringBuilder and toString() calls of the code below:

@Override
public String toString() {
    StringBuilder builder = new StringBuilder();
        builder.append("[Id: ").append(id)
                .append(", Name: ").append(name)
                .append(", Description: ").append(description)
                .append(", StartDate: ").append(startDate)
                .append(", EndDate: ").append(endDate)
                .append(", Note: ").append(note)
                .append("]");

        return builder.toString();
}

This second alternative, is really the best possible? Or is there another approach that I should adopt? Consider those toString methods being called from a loop statement.

Unfortunately, I'm not very familiar with memory tests, so if is possible to write tests for that, I'll be very glad to know about that.

Thanks in advance.

like image 203
Bruno Gasparotto Avatar asked Oct 17 '13 15:10

Bruno Gasparotto


People also ask

Why do we override toString method in pojo?

It is because this method was getting automatically called when the print statement is written. So this method is overridden in order to return the values of the object which is showcased below via examples.

What will happen if we don override toString () method?

There will not be enough information about state or properties of object. So, whenever you use or print a reference variable of type in which toString() method is not overrided, you will get an output like above. You will not get what the object actually has in it.

What does StringBuilder toString do?

The toString() method of the StringBuilder class is the inbuilt method used to return a string representing the data contained by StringBuilder Object. A new String object is created and initialized to get the character sequence from this StringBuilder object and then String is returned by toString().

Does StringBuilder toString allocate?

As @zambari mentioned in the comment, StringBuilder allows to create only one resulting string for several concatenations. But still, every . ToString() call will result in allocation.


1 Answers

As far I know, String is a immutable class. (refer to the javadoc), so, if I implement a method to receive such output, I may have many objects being created because of my concatenations:

Nope. As you're performing all the concatenation in a single large expression, the compiler will pretty much just create the StringBuilder-equivalent code for you.

But notice new StringBuilder and toString() calls of the code below:

Um, yes - and? It would be unusual to create a toString method which used various different field values but didn't create a string.

There's no memory leak here. Yes, you'll create a StringBuilder and String, but they'll be garbage collected appropriately.

Feel free to use either of these forms - or String.format, perhaps - whatever you find simplest to read. If you use the first form, I'd reformat it to have one description and one field value per line:

return "["
    + "Id: " + id 
    + ", Name: " + name 
    + ", Description: " + description
    + ", StartDate: " + startDate 
    + ", EndDate: " + endDate 
    + ", Note: " + note
    + "]";

At this point it looks more like the second form, in terms of readability and ease of adding/removing fields.

like image 161
Jon Skeet Avatar answered Oct 12 '22 03:10

Jon Skeet