Quantcast
Channel: Alexandru V. Simonescu
Viewing all articles
Browse latest Browse all 17

Clean Java immutability

$
0
0

An immutable class is just a simple class whose instances cannot be modified. You provide all field values when creating the instance and they cannot be changed for the lifetime of the object. As you may probably know, Java already has some immutable types as String (string concatenations is not efficient, remember?), BigInteger, BigDecimal.

Some good reasons to design immutable classes:

  • Easier to design, implement and use.
  • Less prone to errors.
  • More secure. Can be freely shared.
  • Are inherently thread-safe; they require no synchronization.

This brief blog post aims to give you an overview of different approaches to build and auto generate immutable classes on Java in a cleaner way. It will talk about two popular libraries focused on generating code: Immutables and AutoValue, also a bit of Guava’s immutables collections.

It’s not a comparative between them, as i think they are both great and it’s you who must choose the one who better adapts to your codebase and needs.

Plain java immutables

To make your classes immutable, you should follow some basic steps:

  • The class cant’t be extended. Making the class final should do the job, this way you prevent malicious subclassing that can alter his state.
  • All fields are final. As setting your fields as final you will need to pass all the values through constructor or create a builder pattern.
  • Make fields private. I think it doesn’t need more explanation, if public you can still access and change fields values.

Let’s see how a immutable class will look in Java:

publicfinalclassAutobot{privatefinalStringname;privatefinalStringfullname;privatefinalBooleanleader;privatefinalStringgroup;publicAutobot(Stringname,Stringfullname,Booleanleader,Stringgroup){this.name=name;this.fullname=fullname;this.leader=leader;this.group=group;}publicStringname(){returnname;}publicStringfullname(){returnfullname;}publicBooleanleader(){returnleader;}publicStringgroup(){returngroup;}}

All fields are private and final, as also the class, and there aren’t any mutations methods.

In case we need a method that returns instance of same class, you should always return a new instance. Imagine our Autobot class has a method called fusion(Autobot) where it takes another Autobot instance and makes a fusion between then.

publicAutobotfusion(Autobotautobot){returnnewAutobot(name.concat(autobot.name()));}

In the remaining article you will find some nice time saving tools for auto generating immutables structures. Why using code generators? Because it will save you time; are well tested; no magic involved, just generated code at buildtime; and you’ll be more happy.

Android: For the next auto generation libraries, you will need configured the APT(annotation processor tool) in Android Studio.

Immutables library

Above you can see how to build an immutable class in plain Java. It really doesn’t require to write lot of code, but sometimes you have many fields, or maybe you’re using a Builder pattern and you’ll have to write lot of boilerplate code. That seems a perfect job for code generation tools!

Now let’s see how would we create an immutable class using Immutables library.

importorg.immutables.value.Value;@Value.ImmutablepublicabstractclassDecepticon{publicabstractStringname();publicabstractStringfullname();publicabstractBooleanleader();publicabstractStringgroup();}

Using the @Immutable annotation and a properly configured IDE, the library will build an immutable extension of the class. In case of Immutables it ads the Immutable[NameOfClass] prefix by default, but it let’s you configure the generation style.

ImmutableDecepticondecepticon=ImmutableDecepticon.builder().name("Megatron").fullname("Megatron Galvatron").group("Decepticons").leader(true).build();

For the above Decepticon class, it generated a 280 lines immutable extension class with also some very useful methods as copyOf(Decepticon), toString(), hashCode(), equals(), and a nice fluent builder as you can see above.

A nice feature is that you can also declare you immutable type as interfaces.

That leds you to multiple extension between interfaces, simulating kind of multiple inheritance:

@Value.ImmutablepublicinterfaceTransformerextendsAutobot,Decepticon{// it will generate and fields extended from Autobot and Decepticon}

There are lot of more cool and useful features, if we don’t want a builder pattern we can simply indicate Immutables to generate a constructor with the fields we annotate.

importorg.immutables.value.Value;@Value.ImmutablepublicinterfaceCar{enumMotorType{DIESEL,GAS}@Value.ParameterStringmanufacturer();@Value.ParameterMotorTypemotorType();}// create instanceImmutableCarcar=newImmutableCar("Nissan",Car.MotorType.GAS);

Ah! Immutables it even supports Guava’s _Optional_ type!

AutoValue library

AutoValue is a library built by the guys at Google and forms part of Auto project. A collection of source code generators for Java like AutoFactory, AutoService and some common utilities for writing code generators.

The key point as above, is simple. You write an abstract class and AutoValue implements it.

Same example class as above will be written like this:

importcom.google.auto.value.AutoValue;@AutoValueabstractclassAutobot{abstractStringname();abstractStringfullname();abstractBooleanleader();abstractStringgroup();}

After building the project, AutoValue would have auto generated the AutoValue_Autobot class.

AutoValue_Autobotautobot=newAutoValue_Autobot("Bumblebee","Bumblebee Autobot",false,"Autobot");

That’s nice but the usage of third party library as AutoValue shouldn’t be visible in your code. There’s a way to leave it cleaner and API invisible.

importcom.google.auto.value.AutoValue;@AutoValueabstractclassAutobot{publicstaticAutobotcreate(Stringname,Stringfullname,Booleanleader,Stringgroup){returnnewAutoValue_Autobot(name,fullname,leader,group);}abstractStringname();abstractStringfullname();abstractBooleanleader();abstractStringgroup();}

Now the creation of Autobot instances becomes more API transparent.

Autobotauto=Autobot.create("Bumblebee","Bumblebee Autobot",false,"Autobot");

If you open the generated class, as Immutables library, it also generated equals(), toString() and hashCode() methods for you, it even does some parameters validation.

importcom.google.auto.value.AutoValue;@AutoValueabstractclassDecepticon{abstractStringname();abstractStringfullname();abstractBooleanleader();abstractStringgroup();staticBuilderbuilder(){returnnewAutoValue_Decepticon.Builder();}@AutoValue.BuilderabstractstaticclassBuilder{abstractBuildername(Stringname);abstractBuilderfullname(Stringfullname);abstractBuilderleader(Booleanleader);abstractBuildergroup(Stringgroup);abstractDecepticonbuild();}}

Builders can also be generated, perhaps it involves a bit more writing as Immutables but you may contrast benefits of both libraries and choose which one to use.

The usage of the builder patterns, in my opinion, makes your code more readable and clean.

Decepticondecepticon=Decepticon.builder().name("Kakuryu").fullname("Kakuryu Decepticon").leader(false).group("Decepticons").build();

Another great AutoValue feature are extensions, you can build your own extensions, i won’t explain here how to do it, out there are lot of interesting articles, like Jake’s Wharton AutoValue Extensions.

Guava

Guava also offers lot of help while working with immutables classes, the difference is that Guava won’t generate code for you. It will just give you some immutable collections.

  • ImmutableList
  • ImmutableSet
  • ImmutableSortedSet
  • ImmutableMap
  • ImmutableSortedMap
  • ImmutableMultiset
  • ImmutableSortedMultiset
  • ImmutableMultimap
  • ImmutableListMultimap
  • ImmutableSetMultimap
  • ImmutableBiMap
  • ImmutableClassToInstanceMap
  • ImmutableTable

The usage is based on static classes, iterators and helpers.

publicstaticfinalImmutableSet<String>COLOR_NAMES=ImmutableSet.of("red","orange","yellow","green","blue","purple");finalImmutableSet<Bar>bars=ImmutableSet.copyOf(bars);// defensive copy!

If interested in Guava, i gave an introductory talk called “Cleaner code with Guava”, it also has an example repository.


Viewing all articles
Browse latest Browse all 17

Trending Articles