views:

1242

answers:

14

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?

+9  A: 

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.

tehblanx
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
Object creation *can* be expensive but usually is not.
Eddie
There are algorithms for this. Open on my desk is a copy of "Purely Functional Data Structures". Worth a read.
Tom Hawtin - tackline
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
Defensive copying due to mutability can also cause this.
parkr
@Tom Thanks for the recommendation. I'll look into it!
tehblanx
Many garbage collected languages recycle objects as opposed to allocating and creating new ones, dramatically reducing instantiation costs.
jordan002
+2  A: 

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
nothing in the beans spec precludes immutability though (at least nothing I can think of).
TofuBeer
I don't think JavaBeans makes a particularly high recommendation.
Tom Hawtin - tackline
+1  A: 

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
A: 

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
Please leave a comment with reason when down voting...
Jorn
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
A: 

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
A: 

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
+8  A: 

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 temporany objects (e.g. String concat was a problem in the past).

dfa
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
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
+3  A: 

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
+1  A: 

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
A: 

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
I don't see what the problem is.
Tom Hawtin - tackline
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
A: 

for a good approach about immutability see clojure way to do it

http://clojure.org

all data collections are primer, and immutable.. and when or add or update something, it dont create a new immutable object but creates a branch in the tree with the new elements ..

everything is immutable , and theres no memory headaches.. its the most clever approach to concurrency.. no locks needed... the data can be readed concurrently, with write threads at the same time.

no deadlocks, no syncronization needed..

and if you need ACID transactions you could use the STM..

that guy was tired of suffering with deadlocks and clumsy coding when threads and mutable stuffs where in the same place.. it just dont work..

Fabio Kaminski
A: 

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..

fabiokaminski
+2  A: 

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

Tony Morris
A: 

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