Why shouldn't I use immutable POJOs instead of JavaBeans?

16,346

Solution 1

Prefer JavaBeans When

  • you have to interact with environments that expect them
  • you have lots of properties for which it would be inconvenient to do all initialization on instantiation
  • you have state that is expensive or impossible to copy for some reason but requires mutation
  • you think at some point you may have to change how properties are accessed (e.g. moving from stored to calculated values, access authorization, etc.)
  • you want to conform to coding standards that mindlessly insist it is somehow more "object-oriented" to use JavaBeans

Prefer Immutable POJOs When

  • you have a small number of simple properties
  • you do not have to interact with environments assuming JavaBean conventions
  • it is easy (or at the very least possible) to copy state when cloning your object
  • you don't ever plan on cloning the object at all
  • you're pretty sure that you don't ever have to modify how properties are accessed as above
  • you don't mind listening to whining (or sneering) about how your code isn't sufficiently "object-oriented"

Solution 2

I was surprised that the word Thread did not appear anywhere in this discussion.

One of the main benefits of immutable classes is that they are inherently more thread safe due to no mutable, shared state.

Not only does this make your coding easier, it'll also give you two performance benefits as a side effect:

  • Less need for synchronization.

  • More scope for using final variables, which can facilitate subsequent compiler optimisations.

I am really trying to move towards immutable objects rather than JavaBean style classes. Exposing the guts of objects via getters and setters should probably not be the default choice.

Solution 3

Well it depends on what you're trying to do. If your working with a persistent layer, and you fetch some row from the database into a POJO, and you want to change a property and save it back, using JavaBean style would be better, especially if you have a lot of properties.

Consider that your person, has a lot of fields like, first, middle, last name, date of birth, family members, education, job, salary etc.

And that Person happens to be a female that just got married and accepted to have her last name changed, and you need to update the database.

If you're using immutable POJO, you fetch a Person object representing her, then you create a new Person object to which you pass all the properties that you didn't change as they are, and the new last name, and save it.

If it were a Java bean you can just do setLastName() and save it.

It's 'Minimize mutability' not 'never use mutable objects'. Some situations work better with mutable objects, it's really your job to decide if making an object mutable will better fit your program or not. You shouldn't always say 'must use immutable objects', instead see how many classes you can make immutable before you start hurting yourself.

Solution 4

Summarizing other answers I think that:

  • Inmutability facilitates correctness (structs can be passed by reference and you know nothing will be destroyed by a faulty/malicious client) and code simplicity
  • Mutability facilitates homogeneity: Spring and other frameworks create an object with no arguments, set object properties, and voi là. Also make interfaces easier using the same class for giving data and saving modifications (you don't need get(id): Client and save(MutableClient), being MutableClient some descendant of Client.

If there were an intermediate point (create, set properties, make inmutable) maybe frameworks would encourage more an inmutable approach.

Anyway I suggest thinking in inmutable objects as "read only Java Beans" stressing the point that if you are a good boy and don't touch that dangerous setProperty method all will be fine.

Solution 5

From Java 7 you can have immutable beans, the best of both worlds. Use the annotation @ConstructorProperties on your constructor.

public class Person {
    private final String name;
    private final Place birthPlace;

    @ConstructorProperties({"name", "birthPlace"})
    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}
Share:
16,346

Related videos on Youtube

Jonas
Author by

Jonas

Passionated Software Developer interested in Distributed Systems

Updated on May 03, 2020

Comments

  • Jonas
    Jonas about 4 years

    I have implemented a few Java applications now, only desktop applications so far. I prefer to use immutable objects for passing the data around in the application instead of using objects with mutators (setters and getters), also called JavaBeans.

    But in the Java world, it seems to be much more common to use JavaBeans, and I can't understand why I should use them instead. Personally the code looks better if it only deals with immutable objects instead of mutate the state all the time.

    Immutable objects are also recommended in Item 15: Minimize mutability, Effective Java 2ed.

    If I have an object Person implemented as a JavaBean it would look like:

    public class Person {
        private String name;
        private Place birthPlace;
    
        public Person() {}
    
        public setName(String name) {
            this.name = name;
        }
    
        public setBirthPlace(Place birthPlace) {
            this.birthPlace = birthPlace;
        }
    
        public String getName() {
            return name;
        }
    
        public Place getBirthPlace() {
            return birthPlace;
        }
    }
    

    And the same Person implemented as an immutable object:

    public class Person {
        private final String name;
        private final Place birthPlace;
    
        public Person(String name, Place birthPlace) {
            this.name = name;
            this.birthPlace = birthPlace;
        }
    
        public String getName() {
            return name;
        }
    
        public Place getBirthPlace() {
            return birthPlace;
        }
    }
    

    Or closer to an struct in C:

    public class Person {
        public final String name;
        public final Place birthPlace;
    
        public Person(String name, Place birthPlace) {
            this.name = name;
            this.birthPlace = birthPlace;
        }
    }
    

    I could also have getters in the immutable object to hide the implementation details. But since I only use it as a struct I prefer to skip the "getters", and keep it simple.

    Simply, I don't understand why it's better to use JavaBeans, or if I can and should keep going with my immutable POJOs?

    Many of the Java libraries seem to have better support for JavaBeans, but maybe more support for immutable POJOs gets more popular over time?

    • matt b
      matt b almost 14 years
      I think you mean Item 15: Minimize mutability, not *Minimize immutability"
    • Jonas
      Jonas almost 14 years
      @matt: Thanks =) I have updated it now.
    • whiskeysierra
      whiskeysierra almost 14 years
      Your immutability approach is great, saves you a lot of thread issues. +1
    • Neil McGuigan
      Neil McGuigan over 10 years
      You would need a default constructor if using JPA
  • lunohodov
    lunohodov almost 14 years
    The idea of IoC/DI is based on setting/injecting state, this is why immutability is not so popular in Spring. However Joda-Time is a good example of immutability done right.
  • Andrei Fierbinteanu
    Andrei Fierbinteanu almost 14 years
    You can use constructor args to inject dependencies with spring as well, it just seems that not many people do that (possibly because when you have a lot of dependencies, having a 10+ parameter constructor is scary).
  • Jonas
    Jonas almost 14 years
    @lunohodov: I have used Google Guice for DI/IoC and there is no problem to do dependency injection to the constructor.
  • extraneon
    extraneon almost 14 years
    +1 for the listing, and almost -1 for your name :) After all, everyone knows it's my opinion which is correct. Everyone being defined in a Discworld sense of course.
  • Jonas
    Jonas almost 14 years
    Bounds checking and input validation can be done in the constructor. If the input is invalid or out of bound, I don't want to create an object.
  • Admin
    Admin over 13 years
    Your second point in beans is not in favour of beans, but in favour of the Builder pattern. You can still construct an immutable object.
  • user1558501
    user1558501 over 12 years
    You don't mention threading with the immutable POJOs, which is by far one of the biggest reasons to use them. Another important item is simplicity - when an object doesn't change, it's easier to work with in the long run. Also, with immutable POJOs, you don't need to worry about cloning the object in general, you can just pass it around.
  • chakrit
    chakrit almost 11 years
    How do you build object graphs that might have circular references such that those objects are immutable? Is this possible? For example I want class A and B to be immutable but A needs a reference to B and B needs a reference to A. Is there a way to do this?
  • supercat
    supercat over 10 years
    In general, it's easiest to work with things (especially in a multi-threaded environment) if data is stored using immutable-once-created references to mutable objects or mutable references to immutable objects. Having freely-mutable references to mutable objects makes things more complicated. Note that if X and Y refer to the same object and one wants to change X.something, one may keep the identity of X and change Y.something, or leave Y.something unchanged and change the identity of X, but one cannot keep the identity of X and the state of Y while changing the state of X.
  • supercat
    supercat over 10 years
    Those who push the use immutable objects sometimes fail to recognize the importance of object identity, and the fact that mutable objects can have an immutable identity in a way that immutable objects cannot.
  • Silviu Burcea
    Silviu Burcea over 10 years
    "you don't ever plan on cloning the object at all" why is that? Maybe I want a new entity based on existing entity. Is that wrong? What about copy constructor?
  • Guillaume
    Guillaume almost 10 years
    What about introspection with immutable object ? plenty of libraries use getter/setter to perform automatiion (data binding, ORM, ...) ?
  • pyb
    pyb over 8 years
  • dsmith
    dsmith almost 8 years
    I would agree that the best of both worlds would be for libraries and frameworks to move to a immutable approach. The advantages of immutable are intrinsic, whereas the advantages of mutable are incidental.
  • dsmith
    dsmith almost 8 years
    Many of the points here in favour of Mutable, as others have commented, can be addressed using the Builder Pattern, and many of the frameworks have been enhanced recently to have some support for immutable objects. In my opinion, immutable objects are objectively better for most problem domain objects. The barrier to adoption is the Java language itself. The builder pattern requires too much maintenance overhead for most developers. This can be mitigated somewhat using "lombok project", but languages with comprehensive structuring and destructuring based on pattern matching are better.
  • dsmith
    dsmith almost 8 years
    But your example is almost never what needs to be done in "real" applications. Usually your updated data object needs to be passed to a validation framework (Hibernate Validator, Spring Validator, etc) where the object is subjected to various operations possibly written by different developers. If the object is mutable, you don't know if you are working with the same data that was passed in (if some validation executed prior to yours mutated the object in place). It makes the validation process less determinant, more dependent on strict order, and unparallelizable.
  • dsmith
    dsmith almost 8 years
    In addition, a "real" application will probably have some sort of in-memory or distributed cache (EHCache, etc) that contain your domain objects. If you know your objects are immutable, you don't need to incur the overhead of copy-on-read. You can safely retrieve and use the in-memory object without worrying about cache integrity. IMHO, for business domain objects of this sort, you always want immutable objects. Mutable objects are OK for local scope and a few other specialized cases that I don't have the characters to get into here.