35

The advantages of immutable objects in Java seem clear:

  • consistent state
  • automatic thread safety
  • simplicity

You can favour immutability by using private final fields and constructor injection.

But, what are the downsides to favouring immutable objects in Java?

i.e.

  • incompatibility with ORM or web presentation tools?
  • Inflexible design?
  • Implementation complexities?

Is it possible to design a large-scale system (deep object graph) that predominately uses immutable objects?

parkr
  • 3,188
  • 5
  • 35
  • 39
  • 3
    One disadvantage of immutable objects is higher levels of object creation and copying. This can, but not always, be a significant overhead on your system. – Peter Lawrey Jun 01 '10 at 12:28
  • We recently made mutable a lot a classes in our system. The biggest disadvantage to me was readability. 75% of code was dealing with creating instances of builders, especially heavy when we had a graph of objects where we wanted to change only an attribute deep in the graph. A maintenance nightmare that no code generator would make you avoid typing it. – Gilles Philippart Jun 14 '10 at 08:10
  • 1
    @parkr I wrote an ORM that will work with immutable objects called [**JIRM**](https://github.com/agentgt/jirm) but your right in that there are not many others. – Adam Gent Nov 07 '12 at 15:20
  • check out this `@Immutable` annotation from [jcabi-aspects](http://www.jcabi.com/jcabi-aspects/annotation-immutable.html) – yegor256 Sep 03 '13 at 09:21
  • 1
    @PeterLawrey - Counter intuitively, in my experience immutable objects can actually reduce object churn - consider an in memory cache of complex mutable objects - to make sure that the cache is not corrupted it is necessary to clone instances from within it and return these. With immutable objects, the instances themselves can be returned. In many systems, this alone can lead to a much lower rate of object creation and copying. – tofarr Oct 29 '13 at 10:43
  • @tofarr good point, I wouldn't return collections in the first place as building it creates garbage even if you don't need to copy the keys/values/elements. I would visit or perform the task of each element, or I would trust the caller not to mess with mutable objects. Closures will help with visitor pattern usage. – Peter Lawrey Oct 29 '13 at 18:05
  • @tofarr: I wish it were easier to create proxy objects (i.e. a thing which encapsulates a reference to something that implements an interface, and implements the interface by chaining its members to those of the encapsulated object), so as to facilitate the implementation of classes that implement ReadableFoo, MutableFoo, ReadonlyFoo, and ImmutableFoo without tons of duplicated code. – supercat Dec 30 '13 at 20:11
  • @tofarr: Trying to do "perfect" copy-on-write is expensive, but if one can tolerate some "unnecessary" copies, and can usually predict whether copies will need to be mutated or shared, most of the benefits of copy-on-write can be obtained, cheaply. Unfortunately, I don't know how to avoid lots of boilerplate code. – supercat Dec 30 '13 at 20:21

17 Answers17

19

But, what are the downsides to favouring immutable objects in Java? incompatibility with ORM or web presentation tools?

Reflection based frameworks are complicated by immutable objects since they requires constructor injection:

  • there are no default arguments in Java, which forces us to ALWAYS provide all of the necessary dependencies
  • constructor overriding can be messy
  • constructor argument names are not usually available through reflection, which forces us to depend on argument order for dependency resolution

Implementation complexities?

Creating immutable objects is still a boring task; the compiler should take care of the implementation details, as in groovy

Is it possible to design a large-scale system (deep object graph) that predominately uses immutable objects?

definitely yes; immutable objects makes great building blocks for other objects (they favor composition) since it's much easier to maintain the invariant of a complex object when you can rely on its immutable components. The only true downside to me is about creating many temporary objects (e.g. String concat was a problem in the past).

Jezor
  • 3,253
  • 2
  • 19
  • 43
dfa
  • 114,442
  • 31
  • 189
  • 228
  • Using the Builder pattern is one way of making the construction of immutable objects safer and simpler. Maintaining Builders can be a pain without generated code however. – Peter Lawrey Jun 01 '10 at 12:27
  • There are workarounds for the lack of argument names with Java's reflection API. Paranamer (http://paranamer.codehaus.org/) is a pretty good library that hacks around the issue. – Rafael de F. Ferreira Sep 10 '10 at 15:22
  • @dfa I had similar parameter problems while developing my immutable ORM: [**JIRM**](https://github.com/agentgt/jirm). I also had to combat the immutable object constructor overriding problem by generally always using static factories methods. There are still some annoying things like Spring where you do not have all the properties set on construction. For that I had to rely on Guava's Suppliers so that the fields would be final (arguable the object is not immutable) but it is threadsafe. – Adam Gent Nov 07 '12 at 15:25
15

With immutability, any time you need to modify data, you need to create a new object. This can be expensive.

Imagine needing to modify one bit in an object that consumes several megabytes of memory: you would need to instantiate a whole new object, allocate memory, etc. If you need to do this many times, mutability becomes very attractive.

AndreiM
  • 4,558
  • 4
  • 36
  • 50
  • You would probably discard the older object in favor of the newly created one. Therefore over the lifetime of your app, the net cost is zero. – Martin OConnor Apr 15 '09 at 15:47
  • Object creation *can* be expensive but usually is not. – Eddie Apr 15 '09 at 15:48
  • 7
    There are algorithms for this. Open on my desk is a copy of "Purely Functional Data Structures". Worth a read. – Tom Hawtin - tackline Apr 15 '09 at 15:50
  • if your object is truly immutable (deeply-nested) you will want to come up with some scheme of component reusage if it is really some megabytes large. – Andreas Petersson Apr 15 '09 at 15:54
  • 10
    Defensive copying due to mutability can also cause this. – parkr Apr 15 '09 at 15:57
  • @Tom Thanks for the recommendation. I'll look into it! – AndreiM Apr 15 '09 at 16:03
  • Many garbage collected languages recycle objects as opposed to allocating and creating new ones, dramatically reducing instantiation costs. – Peter Bratton Apr 15 '09 at 20:22
  • From the [official Java tutorial](http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html): "*Programmers are often reluctant to employ immutable objects, because they worry about the cost of creating a new object as opposed to updating an object in place. The impact of object creation is often overestimated, and can be offset by some of the efficiencies associated with immutable objects. These include decreased overhead due to garbage collection, and the elimination of code needed to protect mutable objects from corruption.*" – Bruno Aug 19 '13 at 14:26
3

Fundamentally, in the real world, the state associated with many particular identities will change. If I ask what is "the present position of Joe's Buick", today it might be a location in Seattle, and tomorrow it might be a location in Los Alamos. It would be possible to define and create a GeographicLocation object whose value will always represent the location where Joe's Buick was at some particular moment in time and would never changes--if today it represents a spot in Seattle, then it will always do so. Such an object, however, would have no continuing identity as "the present location of Joe's Buick".

It may also be possible to define things so that there is a VehicleLocation object which is connected to Joe's Buick such that the object always represents "the present location of Joe's Buick". Such an object could retains its identity as "the present location of Joe's Buick", even as the car moves around, but would not represent a constant geographical location. Defining "identity" may be tricky if one considers the scenario where Joe sells his Buick to Bob and buys a Ford--should the object track "the present location of Joe's Ford" or "the present location of Bob's Buick"--but in many cases such issues may be avoided by using a data model that guarantees that some aspects of object identity will never change.

It isn't possible for everything about an object to be immutable. If an object is immutable, then it cannot have an immutable identity that encapsulates anything beyond its current state. If an object is mutable, however, it can have an immutable identity whose meaning transcends its present state. In many situations, having an immutable identity is more useful than having an immutable state, and in such situations mutable objects are nearly essential. While it is possible in some cases to "simulate" mutable objects by having an immutable object which would search through the most recent version of an immutable objects to find information that may "change" between one version and the next, such an approaches are often extremely inefficient. Even if one could magically receive once per minute a bound book that gave the location of every vehicle everywhere, looking up "Joe's Buick" in the book would take a lot longer than merely asking a "present location of Joe's Buick" object which would always know where the car was.

supercat
  • 77,689
  • 9
  • 166
  • 211
3

If you go for mutability then you will find that whenever you need to call a method that you don't want to have the object change, or you need to return an object that is part of the internal state, you need to make a defensive copy.

If you really look at programs that make use of mutible objects you will find that they are prone to "attack" by modifying:

  • objects passed to constructors
  • objects passed to methods
  • objects returned from methods.

The issue doesn't show up very often because most programs don't change the data (they are in reality immutable by virtue of them never changing).

I personally make every thing I possibly can final. I probably have 90%-95% of all variables (parameters, local, instance, static, exceptions, etc...) marked as final. There are some cases where it has to be mutable, but the vast majority of cases it does not.

I think it might depend on your focus. If you are writing libraries for 3rd parties to use you think about this much more than if you are writing an application that only you (or your team) will maintain.

I find that you can write large scale applications using immutable objects for the majority of the system without too much pain.

TofuBeer
  • 60,850
  • 18
  • 118
  • 163
2

You pretty much answered your own question. The JavaBean specification, I don't believe, mentions anything about immutability, yet JavaBeans are the bread and butter of many Java frameworks.

Julien Chastang
  • 17,592
  • 12
  • 63
  • 89
1

See Functional Java to attain a comprehensive answer to your question.

Tony Morris
  • 3,045
  • 2
  • 29
  • 17
1

The concept of immutable types is somewhat uncommon for people used to imperative programming styles. However, for many situations immutability has serious advantages, you named the most important ones already.

There are good ways to implement immutable balanced trees, queues, stacks, dequeues and other data structures. And in fact many modern programming languages / frameworks only support immutable strings because of their advantages and sometimes also other objects.

Lucero
  • 59,176
  • 9
  • 122
  • 152
1

With an immutable object, if the value needs to be changed, then it must be replaced with a new instance. Depending on the lifecycle of the object, replacing it with a different instance can potentially increase the tenured (long) garbage collection time. This becomes more critical if the object is kept around in memory long enough to be placed in the tenured generation.

Steve Kuo
  • 61,876
  • 75
  • 195
  • 257
1

The problem in java is that one has to live with all those objects, where the class looks like:

class Mutable {
    State1 f1;
    MoreState f2;
    void doSomething() {  // mutate the state, but don't document it }
    void doSomethingElse()  /// mutate the state heavily, do not mention in doc
}  

(Note the missing Cloneable interface).

The problem with the garbage collector is not such a big one nowadays. The VM's are happy with short living objects.

Advances in Compiler/JIT technology will make it possible, sooner or later, to optimize intermediate temporary object creation away. For example:

BigInteger  three =, two =, i1 = ...;
BigInteger  i2 = i1.mul(three).div(two);  

The JIT could notice that the intermediate object i1.mul(three) can be used for the end result and call a variant of the div method that works on a mutable accumulator.

Ingo
  • 36,037
  • 5
  • 53
  • 100
0

The answer is none. There are not any good reasons to be mutable.

You do run in to problems with lots of frameworks(or framework versions) that require mutable objects in order to work with them(Spring I am glaring in your direction). As you work with them and fish through the code you will shake your fist in anger that you need to introduce dirty mutability into an otherwise glorious block of code when it could have been easily avoided.

I'm sure there are limited corner cases(probably more hypothetical that anything) where the overhead of object creation and collection is uncceptable. But I urge the people that would make this argument to look at languages like scala where included collections are immutable by default and then look at the bevy of performance critical apps built on top of that concept.

This is of course hyperbole. In reality, you should go with immutability first, see if it causes you any measurable problems, if it does then introduce mutability, but make sure you can prove it solves your problem. Otherwise you've just created liability for no benefit. In doing this I think you'll find objective cases for "Implementation Complexity" and "Inflexibility" very hard to make.

Adam Gent
  • 47,843
  • 23
  • 153
  • 203
nsfyn55
  • 14,875
  • 8
  • 50
  • 77
0

Some implementations of immutable objects have transactional means to update an immutable object. Similar to how databases provide safe commits and rollbacks. But in apparent contrast with many of the answers here. Immutable objects are never changed. A typical operation would be.

B = append(A,C)

B is a new object. Just like A and C. No modification was made to A or C. Internally a red black tree implementation makes such semantics fast enough to be usable.

The downside is that it is not as fast as making the operations in place. But that only compares a single part of the system. When evaluating possible downsides we need to look at the system as a whole. And I personally don't have a clear picture of the entire impact. Although I suspect immutability wins out at the end.

I know some experts contend there is contention at the top level of the red black tree. And that has a negative effect in throught-put.

Arturo Hernandez
  • 2,749
  • 3
  • 28
  • 36
  • Why have you deleted [your question](http://stackoverflow.com/questions/21712811/partition-or-window-generic-extension-for-ienumerable) about the `PartitionyBy` method? I wanted to post an answer. – Tim Schmelter Feb 11 '14 at 21:05
  • @Tim, sorry. I get frustrated by the "stackoverflow police". I finished coding it and I'll be the first article in my coming soon blog. – Arturo Hernandez Feb 11 '14 at 21:19
  • The answer was simple: `var enu = t.GroupBy(x => x.Order).Select(g => g.Last());`. Also, there weren't any downvotes or close-votes and "have you tried anything" is not an official "SO-police" anymore. http://meta.stackexchange.com/questions/122986/is-it-ok-to-leave-what-have-you-tried-comments/122987#122987 – Tim Schmelter Feb 11 '14 at 21:26
0

in immutable data you dont set things twice... see haskell and scala vals (and clojure of cource)...

for example.. for a data structure.. like a tree, when you perform write operation to the tree, in fact you are adding elements outside of the immutable tree.. after you done.. the tree and the branch are recombined in a new tree.. so like this you could perform concurrent reads and writes very safelly..

in tradicional model, you must lock a value cause it could be reseted any time.. so.. you end up with a very heat zone for threads..since they act sequentially there anyway..

with imuttable data, you dont set things more than once.. its a whole new way of programming.. you may end up using a little bit more memory.. but parallelizing is natural and painless..

0

As with any tool, you have to know when to use it and when not to.

Like Tehblanx points out that if you want to change the state of a variable that holds an immutable object, you have to create a new object, which can be expensive, especially if the object is big and complex. Absolutely true, but that simply means that you have to intelligently decide which objects should be mutable and which should be immutable. If someone is saying that ALL objects should be immutable, well, that's just crazy talk.

I'd tend to say that objects that represent a single logical "fact" should be immutable, while objects that represent multiple facts should be mutable. Like, an Integer or a String should be immutable. A "Customer" object that contains name, address, current amount, date of last purchase, etc should be mutable. Of course I can immediately think of a hundred exceptions to such a general rule. An exception I make all the time is when I have a class that just exists as a wrapper to hold a primitive in some case where a primitive is not legal, like in a collection, but I need to update it constantly.

Jay
  • 26,876
  • 10
  • 61
  • 112
0

In Java, a method can't return multiple objects, like return a, b, c. Returning an array of objects makes the code look ugly. In this situation, I have to pass mutable objects to the method and let it change the states of these objects. However, I don't know whether returning multiple objects is a code smell or not.

0

Immutability, as every other design pattern, should only be used when you need it. You give the example of thread safety: In a highly threaded application, you could favor immutability over the added expense of making it thread safe yourself. However, if your design requires objects to be mutable, don't go out of your way to make them immutable, just because "it's a design pattern".

As for your graph, you could choose to make your nodes immutable and let another class take care of the connections between them, or you could make a mutable node that takes care of its own children and has an immutable value class.

Jorn
  • 20,612
  • 18
  • 79
  • 126
  • Please leave a comment with reason when down voting... – Jorn Jul 12 '09 at 16:07
  • 8
    I strongly object to the notion that immutability "should only be used when you need it". As far as I'm concerned, it should be the other way round: make your classes mutable only when you need it. In the end, mutability is just as much a design pattern as immutability, despite the fact that Java makes mutability easier than immutability. – jqno Aug 15 '09 at 08:30
  • upvote @jqno, mutability = liability. Why expose yourself to the problems unless you really need to? Do you often find yourself using and passing around `StringBuilders` instead of `Strings` because your app is not "highly threaded" – nsfyn55 Aug 05 '12 at 18:30
0

Probably the biggest cost of using immutabile objects in Java is that future developers won't be expecting it or used to that style. Expect to either document heavily or watch alot of your objects spawn mutable peers over time.

That being said, the only real technical reason I can think of to avoid immutable objects is GC churn. For most applications, I don't think this is a compelling reason to avoid them.

The biggest thing I've ever done with a ~90% immutable objects was a toy scheme-esque interpreter, so its certainly possible to do complex Java projects.

Kevin Montrose
  • 22,191
  • 9
  • 88
  • 137
-1

My biggest worry with immutable data structures is how to save/reconstitute them. That is, if a class has final fields, I can't instantiate it and then set its fields.

Zarkonnen
  • 22,200
  • 14
  • 65
  • 81
  • I don't see what the problem is. – Tom Hawtin - tackline Apr 15 '09 at 21:58
  • Say you have a complex object structure you've saved to disk and are ow reloading. If an object cannot be created without setting its variables, you end up with complex constraints on the order in which you must create the objects, because eg object A is referenced by B is referenced by C... – Zarkonnen Apr 15 '09 at 22:58