18

I found an article with an interesting piece of code:

public class Employee {

    private String firstName;
    private String lastName;

    //private default constructor
    private Employee(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public static Employee valueOf (String firstName, String lastName) {
        return new Employee(firstName, lastName);
    }
}

I am really curious in understanding the advantage of creating this kind of classes. I understand that here that an object of this class would be immutable, because there is no way of changing its variable values once initialized. I never did something like this before, and i dont really understand the advantage of it.

  • Why is it a good practice?
  • Could you name a situation where this approach can be used?
  • What about constants or read only variables? Is not that very similar?
  • In the article says, that this is not good for the performance of the application. But why?
frictionlesspulley
  • 11,070
  • 14
  • 66
  • 115
javing
  • 12,307
  • 35
  • 138
  • 211
  • 5
    Mutable state makes it hard to reason about what code does. Look in to functional programming. – Dave Newton Nov 23 '11 at 16:07
  • This class has no accessor methods. Is that on purpose? – zw324 Nov 23 '11 at 16:08
  • Helpful article if you haven't read it yet: http://www.javapractices.com/topic/TopicAction.do?Id=29 – Paul Bellora Nov 23 '11 at 16:08
  • 4
    just a side note: in order for this class to be immutable, the class must be final; the fields must be final, too. – alf Nov 23 '11 at 16:29
  • 4
    That article is terrible! Don't follow its advice, many of the statements it makes are completely wrong. For example, "Quote 1" is wrong: in modern JVMs, object instantiation is extremely fast. "Quote 2" notes that making an instance field public is bad, and then shows a "best approach" that's just as bad: leaking a mutable object (the weekdays array) from a getter. Ugh. I think every single point made in that article has at least one thing wrong with it. – Daniel Pryden Nov 23 '11 at 18:55

7 Answers7

19

The example you have mentioned is of an Immutable Objects. Its widely used concepts in programming languages.

Quoting from the link above. The advantages are

  • are simple to construct, test, and use
  • are automatically thread-safe and have no synchronization issues
  • do not need a copy constructor
  • do not need an implementation of clone
  • allow hashCode to use lazy initialization, and to cache its return value
  • do not need to be copied defensively when used as a field
  • make good Map keys and Set elements (these objects must not change state while in the collection)
  • have their class invariant established once upon construction, and it never needs to be checked again
  • always have "failure atomicity" (a term used by Joshua Bloch) : if an immutable object - throws an exception, it's never left in an undesirable or indeterminate state
Santosh
  • 17,667
  • 4
  • 54
  • 79
  • Good job listing the advantages. I just want to add that an employee class is typically not implemented in an immutable way because none of the above points are needed then, but shared mutable state makes it easier to keep all views of the employee consistent, i.e. any modifications to the Employee will immediately be visible to everyone having a reference to it. If we have to create a new object to represent the changed state, old references still see the old state. Sometimes this is desired, sometimes not, and updating all references to point to the new object is inefficient and cumbersome. – meriton Nov 23 '11 at 20:31
  • 2
    I'm not sure about "allow hashCode to use lazy initialization, and to cache its return value". Do you mean that the object's hash-code is computed and stored in a field the first time its `hashCode()` method is called, with that field being returned thereafter? Because in that case the object is actually *not* immutable, and it loses the "automatically thread-safe" property. Multiple threads can't safely call `hashCode()` at the same time unless they can be certain that the field was already previously initialized (or unless you use `synchronized`/`volatile`/whatnot). – ruakh Nov 23 '11 at 22:17
  • @Ruakh: Yes. I believe there are ways to make it multithreading-safe even in that case - for example, if you can atomically determine that the hash code wasn't calculated yet, and then calculate and return the correct value while also initializing the hash code, then you know that for the local thread of execution the correct value is always the one that is returned. You might calculate the value twice, but I think you'll still always get the right value. I wish I had "Java Concurrency in Practice" handy so I could look up the details (and make sure I'm right). – jprete Nov 23 '11 at 22:37
  • 2
    @jprete: There are ways, certainly, but they require explicit action; it's not at all the same "automatic[] thread-safe[ty]" that a truly immutable object affords. – ruakh Nov 23 '11 at 22:47
  • @jprete: There is no way to atomically determine that the hash-code wasn't calculated and then calculate it if not. As ruakh is implying, if the object is truly immutable in the first place, there is no reason why you can't calculate the hash code in the constructor. – GreenieMeanie Nov 28 '11 at 18:17
4

Immutable classes are:

  • thread-safe by default (concurrent write never occurs)
  • cachable

You can read a lot about them in the conext of the language Java in Effective Java.

frictionlesspulley
  • 11,070
  • 14
  • 66
  • 115
zeller
  • 4,904
  • 2
  • 22
  • 40
  • 9
    `equality check can be done with ==` **Not true**. – Ingo Nov 23 '11 at 16:09
  • Just because a class is immutable does not mean that equality can be checked with "==". String is immutable for example, and in many cases, "==" will not work, where .equals() will. In order for this to work, it would need to be combined with an extended factory that ensures that no more than one instance ever exists for "equal" values. – ziesemer Nov 23 '11 at 16:10
  • Ok, I removed it, but if I have total instance control over the class, I can compare them with ==, I meant what ziesemer wrote. – zeller Nov 23 '11 at 16:13
  • How would concurrent write take place? The example doesn't provide any way to write back in object after it is created. – Obaid Maroof May 29 '13 at 07:11
3

The main advantage of immutable classes is thread-safety. Most problems with threading come from having shared, mutable state. By making objects immutable, it is far easier to reason about them especially in multi-threaded environments.

The article says "creating immutable objects can hit performance of an app." I'm not sure why it says this. It's totally wrong. There is nothing inherent about immutable objects that could affect the application's performance.

Jack Edmonds
  • 31,931
  • 18
  • 65
  • 77
  • Nothing at all? Creating a new object, and copying its entire state, is as fast as updating a single field? – meriton Nov 23 '11 at 22:33
3

-Why is it a good practice?

Because you can pass the class around and be sure it will never be modified by a "rogue" code. Same for Java Strings, they're immutable.

-Could you name a situation where this approach can be used?

It's very useful on big projects where many teams work together, or when designing a framework or an API. In these situations, since you're not responsible of parts of the code, you can never trust that an object you pass to other parts of the code won't be altered. Use immutability if you need to ensure the object won't be modified.

-What about constants or read only variables? Is not that very similar?

Not in Java because we have neither const nor read-only. All we have is the final keyword that ensures an object reference won't be modified beyond first assignment. But the underlying object can still be modified even if the reference can not. Immutable classes ensure an object state won't be altered after creation.

-In the article says, that this is not good for the performance of the application. But why?

Because every time you need to modify the object, you need to create new instances. Same for Strings, you can't do myString.append("42"), you need to do myString = myString+"42", which creates a new String object.

solendil
  • 8,432
  • 4
  • 28
  • 29
  • 2
    I almost upvoted, except for the comments about performance, because they're wrong. Yes, using immutable objects means you're allocating a lot more objects, but in a modern JVM implementation, that should be lightning fast. – Daniel Pryden Nov 23 '11 at 18:45
  • Yes, the allocation is not that expensive, but the new operator does not just allocate an object, it also invokes the constructor. In the above example, String concatenation involves copying the *content* of the entire String, which can get expensive for large or frequently copieds Strings. – meriton Nov 23 '11 at 20:38
  • The cost of allocating a new copy of an immutable object is partially (or completely!) made up for by the fact that you don't need to make defensive copies any more. My experience is that defensive copying of value objects is far more frequent than modification, so if the object is immutable you're actually making fewer copies. – jprete Nov 23 '11 at 22:29
  • For value objects I entirely agree - but `Employee` is not a value object. – meriton Nov 25 '11 at 22:29
2

If you are using hashTables, having immutable objects is good because you dont need to recalculate the hashCode when the state of the object changes(as they are unchangeable).

Zavior
  • 6,412
  • 2
  • 29
  • 38
1

The article says:

To make a class immutable you can define its all constructors private and then create a public static method to initialize and object and return it.

Actually, that is wrong. These two concepts aren't really related.

E.g. you could declare the constructor of your Employee class public and it would still be immutable.

Or you could pass a mutable Object as a parameter to the factory method or declare a mutator method

-> Employee would be mutable although you're using a factory method and a private constructor.

Puce
  • 37,247
  • 13
  • 80
  • 152
0

In your given example he is making constructor as private, and thus controlling the object creation from outside directly.

Meaning : Since constructor is private, you can't do

Employee e = new Employee("steve","jobs"); 

from outside of this class.

By doing so, the programmer of this class, is taking object creation for this class into his control.

This is very beneficial, when you are writing very huge Server side class, for which creating an object may take lot of memory due to its size. Now how do you protect from your clients, of not creating more objects for your class?

Answer for above question is simple, by making your constructor private and you yourself creating objects for your class when ever you want in static method. Note: Static methods can be accessed directly by using class name.

Note: This kind of design patterns will be heavily used in singleton design patterns, which requires only one object for a given class.

user1923551
  • 4,684
  • 35
  • 29