post-images/unnecessary-generated-objects/cover.jpg

Unnecessary Generated Objects

First of all, Hello 🙏🏼 It's me again 🤗. Today we will continue where we left off and discuss the first unit of the Effective Java book, item 6 of Creating and Destroying Objects.

In this article, we will talk about unnecessary objects that occur while developing. These objects may be troubling our system more than we think. Let's start with the questions again; What are unnecessary created objects? What objects can we use over and over again? What happens if I create it over and over again? I will try to answer questions such as.

We have to choose one of two ways when using our classes. Shall we define it once and use it continuously? Or should we define and use a new one each time? Defining it once and using it continuously will make our application faster, readable and, handsome😎. If an object is immutable, that object can always be reused.

Instead of creating an object with a constructor with reference to previous articles, using an instance with Static Factory is of great benefit to us here. eg; Boolean.valueOf(String) Why should I constantly create objects and fill the memory unnecessarily when I can use an instance of the Boolean class? Some objects are much more expensive to create than others. This cost comes from the process. For example, when we want to check if a string is a valid Roman Numeral, the best way to do this is a regex and this operation is considered costly.

// Performance can be greatly improved!  
static boolean isRomanNumeral(String s) {
    return s.matches("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");  
}

The problem with this implementation is that it relies on the String.matches method. While string.matches is the easiest way to check if a string matches a regex, it is not suitable for repetitive use where performance is critical. The way to optimize this process would be to cache it. We can do this as follows;

// Reusing expensive object for improved performance  
public class RomanNumerals {  
    private static final Pattern ROMAN = Pattern.compile("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");  
	
    static boolean isRomanNumeral(String s) {
        return ROMAN.matcher(s).matches();  
    }  
}

Here, our gain from speed was 6.5 times. How valuable is it? It is worth remembering at this stage that since these values will be cached, defining them and not using them will also create an unnecessary load for you.

Autoboxing

If Autoboxing is not understood and used correctly, it will be one of the reasons for creating unnecessary objects for us. There are fine semantic distinctions and not-so-subtle performance differences between the primitive and boxed primitive types. Autoboxing blurs the differences but does not completely remove them.

// Hideously slow! Can you spot the object creation?  
private static long sum() {
    Long sum = 0 L;
    for (long i = 0; i <= Integer.MAX_VALUE; i++) {
        sum += i;
    }

    return sum;
}

Considering the above example, a variable that will collect all positive int values has been defined, and the type of this variable must be long because int limits will not be able to satisfy this operation. This program gives the correct result but why is it running slowly? This is because it's just a 1-character error creating 2³¹ instances unnecessarily. Yes, this is because we used Long instead of long. If we had used long instead of Long, the speed of the application would have decreased from 6.3s to 0.59s. The lesson to be learned here is clear; Prefer primites to boxed primitives and keep an eye on unintentional autoboxing.

In the light of all the information above, it would be excessive to think too much and try to "run my entire application faster" while developing. It's usually a good thing to create additional objects to increase the clarity, simplicity, or power of a program. The subject we are examining here is specific to objects with high cost or intensive use. Performance processing for small objects or actions will mess up your code base more. In this case, don't hesitate to copy objects defensively anyway, operations at this scale will be child's play for the JVM.

JavaEffective JavaCreating and Destroying ObjectsAutoboxingStatic FactoryEnum Types