Why do we need an immutable class?

I can’t get what the scripts are where we need an immutable class.
Have you ever faced such a requirement? or you can give us some real example where we should use this template.

+57
java immutability design-patterns
Sep 22 '10 at 13:17
source share
16 answers

The other answers seem to have focused on explaining why immutability is good. This is very good, and I use it whenever possible. However, this is not your question. I will take your question to try to make sure that you get the answers and examples that you need.

I cannot get what are scripts where we need an immutable class.

"Need" is a relative term here. Immutable classes are a design pattern that, like any paradigm / pattern / tool, makes it easy to create software. Likewise, a lot of code was written before the OO paradigm appeared, but count me among programmers who "need" OO. Immutable classes, such as OO, are not strictly needed, but I will act the way I need them.

Have you ever faced such a requirement?

If you do not view objects in the problem domain with the correct perspective, you may not see the requirements for an immutable object. It would be easy to think that the problem area does not require any immutable classes if you are not familiar when it is beneficial to use them.

I often use immutable classes, where I think of a given object in my problem area as a value or a fixed instance . This concept sometimes depends on the perspective or point of view, but ideally it will be easy to switch to the correct perspective in order to identify good candidate objects.

You can better understand where immutable objects are really useful (if not strictly necessary) by making sure you read in different books / online articles to develop common sense how to think about immutable classes. One good article to get you started: Java theory and practice: mutate or not mutate?

I will try to give a few examples below about how you can see objects in different perspectives (mutable and immutable) to clarify what I mean by perspective.

... could you give us some real example where we should use this template.

Since you asked for real examples, I will give you some, but first, start with some classic examples.

Classic value objects

Strings and integers are often considered values. Therefore, it is not surprising that the String class and the Integer wrapper class (as well as other wrapper classes) are immutable in Java. Color is usually considered a value, therefore the immutable class is Color.

Counterexample

In contrast, a car is not usually regarded as an object of value. Modeling a car usually means creating a class that changes state (odometer, speed, fuel level, etc.). However, there are some domains where a car can be an object of value. For example, a car (or, in particular, a car model) can be considered as an object of value in the application for finding the right engine oil for a given car.

Playing cards

Have you ever written a game card program? I did. I could imagine a playing card as a volatile object with a volatile suit and rank. A draw poker hand can be 5 fixed copies, where replacing the fifth card in my hand would mean mutating the fifth copy of the game card into a new card, changing its suit and ivars ranks.

However, I tend to think that a playing card is an immutable object that has a fixed, unchanging suit and rank after creation. My poker hand will be 5 copies, and replacing the card in my hand will discard one of these copies and add a new random copy to my hand.

Map projection

The last example is when I worked on some map code where the map could be displayed in various projections . In the source code, the map used a fixed but mutable copy of the projection (for example, a modified game map above). Changing the map projection meant mutating the projection of the projection map instance (projection type, center point, scaling, etc.).

However, I felt that the design was simpler if I thought of projection as an immutable value or a fixed instance. Changing the map projection meant having a link to the map of another instance of the projection, rather than mutating a fixed instance of the map projection. It also made it easier to capture named projections such as MERCATOR_WORLD_VIEW .

+61
Sep 22 '10 at 14:51
source share

Optional classes tend to greatly simplify design, implementation, and use. An example is String: implementing java.lang.String much simpler than implementing std::string in C ++, mainly because of its immutability.

One particular area in which immutability is particularly important is concurrency: immutable objects can be safely distributed between multiple threads , while mutable objects must be thread safe through careful design and implementation - this is usually not a trivial task.

Update: Effective Java 2nd Edition solves this problem in detail - see paragraph 15: Minimize Volatility.

See also these related posts:

  • non-technical benefits of having an immutable string type
  • Disadvantages to immutable objects in Java?
+36
Sep 22 '10 at 13:21
source share
Effective Java by Joshua Bloch describes several reasons for writing immutable classes:
  • Simplicity - each class is in only one state
  • Thread Safe - since the state cannot be changed, synchronization is not required
  • Recording in an immutable style can lead to more robust code. Imagine that the Strings were not immutable; Any getter methods that returned String would require the implementation to create a protective copy before String was returned, otherwise the client could accidentally or maliciously violate this state of the object.

In general, it’s good practice to make an object immutable unless serious performance problems arise as a result. In such circumstances, mutable builders can be used to create immutable objects, for example. StringBuilder

+35
Sep 22 '10 at 13:24
source share

Hashmaps are a classic example. The key to the card must be unchanged. If the key is not immutable and you change the value on the key so that hashCode () will result in a new value, the map is now broken (now the key is in the wrong place in the hash table).

+11
Sep 22 '10 at 13:21
source share

Java is almost all links. Sometimes an instance is referenced several times. If you change such an instance, it will be reflected in all its links. Sometimes you just don’t want this to improve the reliability and security of the threads. Then an immutable class is useful, so you need to create an instance of new and reassign it to the current link. Thus, the original instance of the other links remains untouched.

Imagine what Java looks like if String changed.

+6
Sep 22 '10 at 13:20
source share

We do not need immutable classes, but they can, of course, facilitate some programming tasks, especially if several threads are involved. You do not need to perform a lock to access an immutable object, and any facts that you have already established regarding such an object will continue to be significant in the future.

+6
Sep 22 2018-10-22
source share

There are various reasons for immutability:

  • Thread safety: immutable objects cannot be changed and its internal state cannot change, so there is no need to synchronize it.
  • It also ensures that everything I send through (via the network) must be in the same state as it was previously sent. This means that no one (bug) can come and add random data to my immutable set.
  • It is also easier to develop. You guarantee that no subclasses will exist if the object is immutable. For example. a String .

So, if you want to send data through a network service and want to get a guarantee that your result will be exactly the same as you sent, set it as unchangeable.

+5
Sep 22 '10 at 13:40
source share

Take the extreme case: integer constants. If I write an expression like "x = x + 1", I want to be 100% trusted that the number "1" will not become somehow 2, regardless of what happens elsewhere in the program.

Now everything is all right, integer constants are not a class, but the concept is the same. Suppose I write:

 String customerId=getCustomerId(); String customerName=getCustomerName(customerId); String customerBalance=getCustomerBalance(customerid); 

It looks simple enough. But if the rows were not immutable, then I would have to consider the possibility that getCustomerName could change customerId, so when I call getCustomerBalance, I get a balance for another client. Now you can say, “Why is there someone in the world who writes the getCustomerName function that will change the identifier? That doesn't make sense.” But this is exactly where you could get in trouble. The person who wrote the above code may find it simply obvious that the functions will not change the parameter. Then comes someone who needs to change another use of this function in order to handle the case when the client has several accounts under the same name. And he says: “Oh, this is a convenient function of the recipient’s name, which is already looking for the name. I’ll just do this to automatically change the identifier to the next account with the same name and put it in a loop ...” And then your program starts mysteriously not work. Will this be a bad coding style? Probably. But this is definitely a problem in cases where the side effect is NOT obvious.

Immutability simply means that a certain class of objects is a constant, and we can consider them as constants.

(Of course, the user can assign the variable "permanent object" to the variable. Someone can write String s = "hello"; then write c = "goodbye"; If I do not make the variable final, I cannot be sure that it will not be changed in my own code block. Like integer constants, assure me that "1" always matches the number, but not "x = 1" will never be changed by writing "x = 2". But I can be trusted that if I have a handle to an immutable object, then no function that I pass can change it it to me, or if I make two copies of this, the change in the variable containing a single copy, will not change the other. Etc.

+5
Sep 22 2018-10-22
source share

I am going to attack this from a different perspective. I find immutable objects that make life easier when reading code.

If I have a mutable object, I never doubt its value if it has ever been used outside my immediate area. Let's say I create MyMutableObject in the local variables of a method, populate it with values, and then pass it to five more methods. ANY ONE of these methods can change the state of my object, so one of two things should happen:

  • I need to track bodies from five additional methods, thinking about my code logic.
  • I need to make five wasteful protective copies of my object to ensure that the required values ​​are passed to each method.

It's hard to talk about my code at first. Secondly, my code suck in performance - I basically mimic an immutable object with copy-on-write semantics anyway, but I do this all the time regardless of whether the called methods really change my state of the object.

If I use MyImmutableObject , I can be sure that what I set is that the values ​​will be for the life of my method. There is no “creepy action at a distance” that will change it from under me, and I do not need to make protective copies of my object before invoking the five other methods. If other methods want to change things for their own purposes , they must make a copy - but they only do this if they really need to make a copy (as opposed to my execution before each call to external methods). I reserve mental resources for tracking methods that may not even be in my current source file, and I save the system from overhead by endlessly making unnecessary security copies just in case.

(If I go beyond the Java world and, say, into the C ++ world, among others, I can become even more complex. I can make objects look like they are mutable, but behind the scenes make them a transparent clone when any state changes - This is copying to record, and no one is wiser.

+5
Sep 22 '10 at 15:07
source share

Using the final keyword does not necessarily make something immutable:

 public class Scratchpad { public static void main(String[] args) throws Exception { SomeData sd = new SomeData("foo"); System.out.println(sd.data); //prints "foo" voodoo(sd, "data", "bar"); System.out.println(sd.data); //prints "bar" } private static void voodoo(Object obj, String fieldName, Object value) throws Exception { Field f = SomeData.class.getDeclaredField("data"); f.setAccessible(true); Field modifiers = Field.class.getDeclaredField("modifiers"); modifiers.setAccessible(true); modifiers.setInt(f, f.getModifiers() & ~Modifier.FINAL); f.set(obj, "bar"); } } class SomeData { final String data; SomeData(String data) { this.data = data; } } 

Just an example demonstrating that the keyword "final" exists to prevent a programmer’s error, and not much more. While reassigning a value that does not have the final keyword can easily happen by accident, going this length to change the value would have to be done intentionally. This is there for documentation and to prevent programmer error.

+1
Sep 22 2018-10-22T00:
source share

Continuous data structures can also help when coding recursive algorithms. For example, say that you are trying to solve the 3SAT problem. One way is to do the following:

  • Please select an invalid variable.
  • Give it a value of TRUE. Simplify the instance by listing the sentences that are now running, and repeat to solve the simpler instance.
  • If the recursion in the case of TRUE fails, assign this variable FALSE instead. Simplify this new instance and repeat it to resolve the problem.

If you have a mutable structure to represent the problem, then when you simplify the instance in the TRUE branch, you need to either:

  • Keep track of all the changes that you are making and undo them all as soon as you realize that the problem cannot be resolved. This has a lot of overhead, because your recursion can go pretty deep, and it's hard to do for code.
  • Make a copy of the instance, and then modify the copy. This will be slow, because if your recursion is several tens of levels, you will need to make many copies of the instance.

However, if you code it correctly, you can have an immutable structure where any operation returns an updated (but still immutable) version of the problem (similar to String.replace - it does not replace the string, it just gives you a new one). The naive way to implement this is to make the "immutable" structure simply copy and create a new one for any modifications, reducing it to the second solution, having a replaceable one, with all this overhead, but you can do it in a more efficient way.

+1
Sep 22 '10 at 3:27
source share

One of the reasons for the “need” for immutable classes is the combination of passing everything by reference and the lack of support for viewing a read-only object (i.e., C ++ const ).

Consider a simple case of a class that has observer pattern support:

 class Person { public string getName() { ... } public void registerForNameChange(NameChangedObserver o) { ... } } 

If the string were not immutable, it would be impossible for the Person class to correctly implement registerForNameChange() , because someone could write the following, effectively changing the person’s name without causing any notice.

 void foo(Person p) { p.getName().prepend("Mr. "); } 

In C ++, getName() returning const std::string& leads to returning by reference and preventing access to mutators, which means immutable classes are not needed in this context.

+1
Sep 22 '10 at 15:36
source share

They also give us a guarantee. The guarantee of immutability means that we can expand them and create new patterns for efficiency that are otherwise impossible.

http://en.wikipedia.org/wiki/Singleton_pattern

+1
Sep 22 '10 at 15:38
source share

One feature of immutable classes that have not yet been called: storing a reference to an object with an immutable class is an effective means of storing all the state contained in it. Suppose I have a mutable object that uses a deeply immutable object to store 50K state information. Suppose further that in 25 cases I want to make a “copy” of my original (mutable) object (for example, to “cancel”); the state may change between copy operations, but usually this does not happen. Creating a “copy” of a mutable object would simply require copying the link to its immutable state, so 20 instances will simply make up 20 links. In contrast, if the state were placed on 50 thousand. Changed objects, each of the 25 copy operations had to create its own copy of the data for 50 thousand. To store all 25 copies, you would need to store a large amount of duplicated data. Despite the fact that the first copy operation will create a copy of the data that will never change, and the remaining 24 operations can theoretically just refer to it, in most implementations there would be no way for the second object to request a copy of information that the immutable copy is already exist (*).

(*) One template that can sometimes be useful is that for mutable objects there are two fields for storing their state - one in mutable form and one in immutable form. Objects can be copied as mutable or immutable and begin life with one or another set of links. As soon as the object wants to change its state, it copies the immutable reference to the mutable (if it has not already been made) and invalidates the immutable. When an object is copied as immutable, if its immutable reference is not specified, an immutable copy will be created, and an immutable reference will be referenced to it. This approach will require several more copy operations than a “full copy on write” (for example, a request to copy an object that has been mutated because the last copy requires a copy operation even if the original object is no longer mutated), but this avoids the complexity of threads that FFCOW entails.

+1
May 2 '12 at 15:51
source share

from efficient Java; An immutable class is simply a class whose instances cannot be changed. All information contained in each copy is provided when it is created, and fixed for the lifetime of the object. The Java platform libraries contain many immutable classes, including String, boxed primitive classes, and BigInteger and BigDecimal. There are many good reasons for this: immutable classes are easier to develop, implement, and use than mutable classes. They are less error prone and safer.

0
Jul 27 '15 at 14:26
source share

By immutability, you can be sure that the behavior will not change, and you will get an additional advantage in performing additional operations:

  • You can use multiple core / processing ( parallel processing ) with (since the sequence no longer matters.)

  • You can cache for expensive work (since you are sure of the same | result).

  • Can be easily debugged (since the launch history will not be a problem) anymore)

0
May 8, '17 at 17:41
source share



All Articles