I've heard that immutable objects are safe, or try to create immutable objects as much as possible, but what is that? I think there are many people
Here I will explain what an immutable object is and how to create an immutable object. Immutable objects can be created regardless of language, but I think I'll explain it in Java.
The explanation is for beginners here, but if you want to read more detailed explanation, please buy the following books. Effective Java 3rd Edition
To put it simply, it is an object that has the same data.
I don't know what it means, so I'll explain it using Java String and StringBuilder. First look at the code below
String str = "A";
for(int i = 0; i < 2 ; i++){
str += "A";
}
System.out.println(str);
The output result is as follows
AAA
This code simply adds A to str twice In the above code, str is declared as a String type, but declaring str as a StringBuilder type does not change the output result.
However, the method of instantiation is different between String and StringBuilder. Let's see what kind of instance will be left in the end
** For StringBuilder ** Since only the same instance as the output result is generated, the final remaining instance is only one AAA.
** For String ** In the case of String, another instance is created each time A is added. Therefore, A, AA, AAA instances remain Instances of A and AA are out of reference and are subject to GC.
As you can see from the above example, StringBuilder has the value of one instance rewritten, while String has another instance without rewriting the value. Generating </ font> color </ font>
StringBuilder only instantiates once, so it's less expensive Since String has created instances many times, the load will be higher accordingly.
Looking at this, there is no point in using String! You may feel, but ** it's a mistake **
StringBuilder is called a mutable object because it rewrites the value String is called an immutable object because it hasn't rewritten its value
As mentioned above, the advantages of StringBuilder lead to improved performance. In this example, A is combined only twice, but if this is 10,000 times, it will not be possible to make a fool of the instance creation cost.
However, even though it is the same instance, the value is rewritten depending on the timing, such as A, AA, AAAAAAA. This is a big problem, and once you make a change, it also affects the objects that reference it.
This means that ** variable objects will have some side effects every time a change is made ** </ font color>
What if it's a String? It costs money to create multiple instances, but one object always keeps the same value. If you want an instance with a different value, create another instance Therefore, it does not affect other objects. That is, ** Immutable objects can be used to ensure that their values do not change ** </ font color>
Immutable objects are also useful for multithreaded programming Immutable objects don't change in value, so you don't have to do things like synchronize with synchronized ... The problem with multithreaded environments is that they are variable objects.
** Immutable objects are inherently thread-safe ** </ font color>
Even if you create a variable object, reducing the variable part as much as possible will help prevent accidents.
So far, you can see how useful immutable objects are. From here, I'll explain how to actually create an immutable object.
If you allow the class to be inherited, the encapsulation will be broken, such as being inherited and adding strange methods. I do not want to cause problems such as immutable object or variable object depending on how it is created even though the type is the same, so declare class so that it can not be inherited
final class TestClass{}
If it is a class of an encapsulated module, it is not visible from the outside, so it is practically impossible to inherit without adding final, but if you do not intend to inherit it, add final to inherit It's common to forbid (the same is true for variable objects)
Immutable objects don't want their values changed, so make them all constants It also sets visibility so that variables are not referenced directly.
private final int num;
private final StringBuilder str;
There is no problem if you declare in the same way regardless of the basic data type and reference data type. In the case of reference data type, it is necessary to change the treatment a little, but it will be described later.
A mutator is an operation that rewrites values such as setters. I don't want to rewrite the value, so of course I don't need a method to do that
First look at the code below
public int getNum(){
return num;
}
public StringBuilder getStr(){
return str;
}
The return value of the getNum method is the basic data type, and the return value of the getStr method is the reference data type. For basic data types, a copy of the value of num is returned, so there is no problem. However, in the case of the reference data type, the problem occurs because the reference is returned as it is.
Since the instance reference can be obtained on the side that called the getStr method, the value inside the str instance can be rewritten.
To prevent that, I tried to improve the previous code
public String getStr(){
String result = str.toString;
return result;
}
The StringBuilder class had a method called the toString method that turns a variable object into an immutable object, so I tried using it. However, this type conversion part is not very important in the "Watch out for getters" description. The important thing is that is copying and returning the value </ font>
Create another copy instance and return a reference to the copy instance By doing this, the caller of the getStr method can use any means to tamper with the copy instance, but it will not interfere with the original instance.
This technique is called ** defensive copy ** By using defensive copy, even a class that handles variable objects like StringBuilder can make the class an immutable object.
There are some caveats when using defensive copy ① Performance may deteriorate In the case of arrays, Lists, etc., performance may be degraded because all the contents must be copied. But keep in mind that immutable objects are worth the price. ② Do not use the clone method The java clone method has some problems, so please do not use it when making a defensive copy
I will put the sample code of the immutable object explained so far. (The constructor part has been added)
final class TestClass{
private final int num;
private final StringBuilder str;
public TestClass(int num,StringBuilder str){
this.num = num;
//Also make a defensive copy here
this.str = new StringBuilder(str);
}
public int getNum(){
return num;
}
public String getStr(){
String result = str.toString;
return result;
}
}
In the sample code above, the constructor is public, but Effective Java recommends a static factory. This also applies to current API development Let's rewrite the sample code a little earlier
final class TestClass{
private final int num;
private final StringBuilder str;
//Prohibiting the use of constructors from the outside
//The following code cannot be used on the caller
// TestClass tc = new TestClass(10,"AAA");
private TestClass(int num,StringBuilder str){
this.num = num;
this.str = new StringBuilder(str);
}
//static factory
public static final TestClass newInstance(int num,StringBuilder str){
return new TestClass(num,str);
}
public int getNum(){
return num;
}
public String getStr(){
String result = str.toString;
return result;
}
}
The calling code looks like this
TestClass tc = TestClass.newInstance(10,"AAA");
In the case of the above code, it will not be a singleton because a new instance of type TestClass will be created each time the newInstance method, which is a static factory, is called. But if you don't want to be a singleton you can use this technique
If you want to make it a singleton, do not use new in the static factory method, just create an instance in advance and return
The advent of DI containers may reduce the chances of calling static factor directly, but this technique is still active.
I introduced what an immutable object is and how to make it.
It is no exaggeration to say that there is no system that does not require immutable objects in any system, so please remember and use it.
Recommended Posts