3 principles to manage your objects elegantly in Java

Image due to Lisa FotiosLearn to use design patterns to manage your objects more effectivelyJava is an object-oriented programming language. As of its definition, objects play huge roles in it. Therefore, learning to manage objects properly can be a cr…


This content originally appeared on Level Up Coding - Medium and was authored by Tech & Math

Image due to Lisa Fotios

Learn to use design patterns to manage your objects more effectively

Java is an object-oriented programming language. As of its definition, objects play huge roles in it. Therefore, learning to manage objects properly can be a crucial key to the performance and success of your Java project. In this article, I summarize 3 principles and ways of implementation to help you achieve more effective management of your objects.

Principle 1: Control the number of instances

Objects allocation can be resources-consuming and can become a bottleneck quickly if it is not managed carefully. One of the most important things is to make sure you do not create an excessive number of instances over some objects. Unnecessary instances can bring a huge cost to your program’s performance both time-wisely and space-wisely. Here, I listed a few ways to avoid creating unnecessary instances creation.

  1. Try to use static factory methods

First, I want to clarify that static factory methods have nothing to do with the factory methods in the design pattern. What is a static factory method? Well, suppose your phone is dying, and you need a charger . Usually, we would go and write Charger getMeACharger = new Charger(). However, do you really want to have a new charger every time you charge the phone? Probably not. A better idea is to get a charger from your desk’s drawer and pick an available charger there. In Java, your desk’s drawer is the factory, and the action of picking an available charger is the method you want. To realize this, we have to make the method static so that we do not need to have an instance of our factory in order to get our charger . In Java, it will look like this:

Above is an example of a static factory method. In this case, our DeskDrawerChargerFactory is the factory, and we can take instances from our factory instead of doing traditional new methods.

In this way, we can control the overall numbers of the objects, and if we need one, we can just invoke the static factory methods to return us an instance and perform operations based on that. Many real-world applications such as JDBC enforce such good practice to limit the number of database connections you can have for your program. If we are allowed to create any number of connections to the database as we want, it is highly likely the database will be overwhelmed with requests and failed to respond properly. Of course, there are a number of additional reasons that you might want to use the static factory method. Using this practice allows you to return the desired subclass of instance to user, which is something normal constructor cannot do; it allows you to make more meaningful names for better readability. For instance, suppose you want a class of complex numbers, the method name like ComplexNumbers.createFromXYCoordinate(double x, double u) or ComplexNumbers.createFromPolarCoordinate(double distance, double angle) seem to be better than ComplexNumbers c = new ComplexNumbers(x,y).

2. Enforce noninstantiability

This idea sounds crazy at first: if we are not allowed to instantiate objects, what is Java for? Well, there are some cases you do want noninstantiability. For instance, sometimes you will write util classes. These util classes do not contain states/attributes, therefore you can directly call their static methods to achieve what you want. Sometimes, if other people are not careful and instantiate such util classes, it can be a waste of resources, especially for those giant util classes with large number of methods. Therefore, you want to ensure that there is no way people can instantiate those classes. One effective way to do that is to set your constructor to be private. Notice that if you do not implement constructor explicitly, Java will provide a default one, and sometimes people can invoke the default one by accident. Thus, check your util classes and make sure there is a private constructor.

3. Watch out for method in library

This is a tricky one, and it heavily depends on your knowledge on the codebase. However, this is quite important. Take a simple example: String concatenation + . Under the hood, the + operation will create a StringBuilder operator and uses it to concatenate our strings together. Consider the following program:

In each of the loops, a StringBuilder object will be constructed, and str = str + i will be roughly translated into StringBuilder builder = new StringBuilder(str); builder.append(i); str = builder.toString(); You see, in this way, we will have 1000 internally constructed StringBuilder objects, and this is probably not what we are hoping for. Instead, try to do the following:

The number of StringBuilder created shrinks from 1000 to 1, and that number might just give your program a boost.

Other examples include String.matches method. It will create internal objects every time you call it. Imagine your server runs this method every 10000 times per second, your performance will be much better if you can find an alternative. One way to do so is to create a static-equivalent of the internal object, and this way you will only need to create that object once for all.

Principle 2: Make instantiation readable and scalable

What do I mean by this? Well, I pretty much mean there are two things we need to look out for.

  1. Constuctor with too many parameters

The first one is that we should use builder pattern for those object with many constructor parameters.

Consider this, we are writing a burger class which requires a component named bun, a component named meat and a component named in-between (cheese, lettuce stuff). Also, we can allow our customers add two extra in-between , so that leaves 5 parameters in total. Since three is required and two are optional, traditionally we need to provide 3 constructors:

As you see, as the number of parameter grows, we have to write more and more constructors. There is a way out by setters. However, still, the setter are not that efficient. To find a better solution, we consider the builder pattern as below:

2. Use Dependency Injection

The second thing worth mentioning is to use dependency injection if possible. Sometimes, we will have a class A that will depend on many other objects, say B, C, D, E. Although we can create them one by one (B, C, D, E), things can quickly unmanageable. What if B also several dependencies and its dependencies have further dependencies? In that case, in order to instantiate one A , we have to instantiate hundreds of classes, and it is even hard for us to figure out the dependency route. This is especially difficult in testing when we try to mock some dependency classes.

Luckily, dependency comes to the rescue! Here, I will not explain further about dependency but to mention that it is a mechanism that allows the computer to auto-inject the dependency class you need into appropriate places. There are tons of dependency injection libraries and I will leave you to discover your favorite by googling the keywords.

Principle 3: Check for possible reference leaks

Yes, you hear me correctly! We do have reference leaks or memory leaks in Java. Although Java takes care of the memory management for us, it cannot take care of all situations. JVM, nowadays, still depends on reference counting as a major mechanism of garbage collection or memory management. Therefore, if we accidentally leave a reference to an object we will not use, it will impact our program and even can bring us to the familiar stackoverflow !!!

Suppose you are implementing a Queue class yourself, and you write pop() method like this:

In this case, we directly return the reference of some element in the array and did not write some statement like data_array[index] = null; . Then, the array will still attach a reference to the object. Suppose you are executing this problematic code in a really large array, the JVM will skip hundreds and thousands of objects that are supposed to be garbage collected! If we cannot detect this in time, the memory is likely to be filled really soon. Therefore, always keep an eye out for potential reference leaks as they can do real damage to your program. One of the frequent places of reference leaks is in the cache. Suppose you store 1 object in cache but it is never hit, and it can sit in your cache for a long period of time depending on your cache evicting algorithm. As the cache will still retain a reference to the object, it cannot be properly cleaned. Sometimes the listeners, callbacks, and even operating system page swapping can cause reference leaks!

Some potential useful practice to fight against reference/memory leaks is to profile your program’s memory to see if there is any anomalies, or you can dive straight into JVM and seek for memory information and do heap dumps (cleaning out heaps for memory).

Those are three principles I summarized for you to better control your Java program’s performance and resources. There is no single perfect solution that fits all the situation, but keep those practices in your mind and they might help you in some common scenarios. Happy learning, happy coding!


3 principles to manage your objects elegantly in Java was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Tech & Math


Print Share Comment Cite Upload Translate Updates
APA

Tech & Math | Sciencx (2022-03-29T19:38:01+00:00) 3 principles to manage your objects elegantly in Java. Retrieved from https://www.scien.cx/2022/03/29/3-principles-to-manage-your-objects-elegantly-in-java/

MLA
" » 3 principles to manage your objects elegantly in Java." Tech & Math | Sciencx - Tuesday March 29, 2022, https://www.scien.cx/2022/03/29/3-principles-to-manage-your-objects-elegantly-in-java/
HARVARD
Tech & Math | Sciencx Tuesday March 29, 2022 » 3 principles to manage your objects elegantly in Java., viewed ,<https://www.scien.cx/2022/03/29/3-principles-to-manage-your-objects-elegantly-in-java/>
VANCOUVER
Tech & Math | Sciencx - » 3 principles to manage your objects elegantly in Java. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/03/29/3-principles-to-manage-your-objects-elegantly-in-java/
CHICAGO
" » 3 principles to manage your objects elegantly in Java." Tech & Math | Sciencx - Accessed . https://www.scien.cx/2022/03/29/3-principles-to-manage-your-objects-elegantly-in-java/
IEEE
" » 3 principles to manage your objects elegantly in Java." Tech & Math | Sciencx [Online]. Available: https://www.scien.cx/2022/03/29/3-principles-to-manage-your-objects-elegantly-in-java/. [Accessed: ]
rf:citation
» 3 principles to manage your objects elegantly in Java | Tech & Math | Sciencx | https://www.scien.cx/2022/03/29/3-principles-to-manage-your-objects-elegantly-in-java/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.