[Effective Java] Remove obsolete object references

Effective Java's own interpretation. I tried to interpret item 7 of the 3rd edition by writing my own code.

Overview

――In logic, even if the object is never used again, the garbage collector may not have a way to know it. --Be aware of when the reference will disappear, and if the garbage collector cannot determine it, intentionally refer to null. --Declare variables as soon as possible and keep the scope to a minimum.

Prerequisite knowledge

Garbage collection

Java has a feature that the garbage collector automatically deletes objects that are no longer referenced.

For example, in the following code, " hoge0 ", " hoge1 ", " hoge2 " objects of String are created in the for loop, but the reference variable hoge slides the reference target in order. The " hoge0 ", " hoge1 " objects are deleted by the garbage collector.

String hoge = null;

for (int i = 0; i < 3 ; i++){
    hoge = "hoge" + i;
}

del-object-Page-1.jpg

On the other hand, the object whose reference remains is not deleted and remains in the memory indefinitely. The following code stores objects in an array, but with hoge [0], hoge [1], hoge [2], " hoge0 ", " hoge1 ", " hoge2 " Since each can be referenced, it will not be deleted by garbage collection and the object will remain in memory.

String[] hoges = new String[3];

for (int i = 0; i < 3; i++) {
    hoges[i] = "hoge" + i;
}

del-object-Copy of Page-1.jpg

Anti-patterns and solutions

Homemade stack

A stack is a Last In First Out data structure. It can be easily implemented using the Deque interface, but here I dare to implement it. Mount by hand.

** Homemade stack class **

public class Stack {

    /**
     *Array for stack
     */
    private String[] hoges;

    /**
     *Current number of stack elements
     */
    private int currentElementCount = 0;

    /**
     *constructor
     *Define the size of the stack
     */
    public Stack() {
        this.hoges = new String[3];
    }

    /**
     *Push to stack
     *
     * @param str string to push
     */
    public void push(String str) {
        hoges[currentElementCount] = str;
        currentElementCount = currentElementCount + 1;
    }

    /**
     *Pop from stack
     *
     * @return Popped string
     */
    public String pop() {
        if (currentElementCount == 0) {
            throw new EmptyStackException();
        }
        currentElementCount = currentElementCount - 1;
        return hoges[currentElementCount];
    }
}

If you do this class, Push, you can certainly get the element, and if you do Pop, you can get the last element, but there is one problem. Since it only shifts the reference number when popping, the object reference itself remains.

del-object-Page-3 (1).jpg

The logic is correct, the popped element will never be used again, but the garbage collector can't tell if it's going to be deleted because the reference remains. In this example, the maximum stack size is 3, so at most 3 objects remain in memory, but large stacks can cause serious memory shortages. This problem can be solved by intentionally putting Null in the corresponding element of the array when popping and deleting the reference to the original object.

del-object-Page-4.jpg

However, if you really want to use the stack, use the Deque interface. Let's do it.

Variable declaration where it is not used

Sometimes variables are declared too early, leaving objects in memory in vain. In the code below, there is a problem with the prefix declaration.

/**
 *Returns a string of numbers up to the specified number of loops
 *Add prefix if length exceeds specified threshold
 *
 * @param limitLength String threshold
 * @param loopCount Number of loops
 * @String created by the return loop
 */
public String hoge(int limitLength, int loopCount) {

    String prefix = "Over" + limitLength + ": ";

    StringBuilder str = new StringBuilder();
    for (int i = 0; i < loopCount; i++) {
        str.append(i);
    }

    if (str.length() > limitLength) {
        return prefix + str;
    } else {
        return str.toString();
    }
}

There are two problems.

--The object remains in memory until it is actually used in the ʻif block. --Because you declare it outside the ʻif block, the object remains in memory even if you enter ʻelse`.

The above problem can be solved by declaring it just before the place where it is really used as follows.

    if (str.length() > limitLength) {
        String prefix = "Over" + limitLength + ": ";
        return prefix + str;
    } else {
        return str.toString();
    }

Note that in the case of a long method, it is often not noticed unexpectedly.

Recommended Posts

[Effective Java] Remove obsolete object references
[Read Effective Java] Chapter 2 Item 6 "Remove obsolete object references"
Java (remove)
Effective Java Chapter 2
Effective Java Chapter 6 34-35
[Java] Object class
Effective Java Chapter 4 15-22
Effective Java Chapter 3
Java object size feeling
Effective Java 3rd Edition Chapter 2 Object Creation and Disappearance
Builder pattern (Effective Java)
Java Object Serialization why & when
Muscle Java Object Oriented Day 1
From Ineffective Java to Effective Java