immutables in java

Post on 15-Jan-2017

540 Views

Category:

Education

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

www.marcus-biel.com

MARCUS BIEL,Software CraftsmanImmutables in Java

The concept of Immutability has always been very important

across all programming languages.

MARCUS BIEL,Software CraftsmanImmutables in Java

MARCUS BIEL,Software CraftsmanImmutables in Java

For a Java developer however, Immutable classes, or simply, "Immutables",

MARCUS BIEL,Software CraftsmanImmutables in Java

have become more important than ever with the release of Java 8.

MARCUS BIEL,Software CraftsmanImmutables in Java

Among many other cool things, this version introduced the concept of

functional programming as well as the new java.time api.

MARCUS BIEL,Software CraftsmanImmutables in Java

Immutable classes play a key role in both of these new features.

MARCUS BIEL,Software CraftsmanImmutables in Java

Because of this, I’ve decided to provide you with

a detailed look at Immutables.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Outline

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

I'll tell you exactly what an Immutable is,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Outline

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

its advantages and disadvantages,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Outline

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

and how to create an Immutable.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Outline

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

I’ll finish by giving you concrete advice on when to use Immutables in your daily work.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

What is an Immutable?

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

So let’s start with the most important question – what is an Immutable class?

Copyright © 2016 Marcus Bielwww.marcus-biel.com

What is an Immutable?

In short, an Immutable class is a class whose instances

cannot be modified.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

What is an Immutable?

The information contained in each immutable object is provided when it is created -

Copyright © 2016 Marcus Bielwww.marcus-biel.com

What is an Immutable?

and is frozen for its lifetime. Once an Immutable object has been created,

it is read only, forever fixed, like a fossil.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

What is an Immutable?

USS Enterprise (NCC-1701)

ImmutableSpaceship enterprise = new ImmutableSpaceship("Enterprise");enterprise.exploreGalaxy();

So if an object is immutable, how can we modify it?

Copyright © 2016 Marcus Bielwww.marcus-biel.com

What is an Immutable?

USS Enterprise (NCC-1701)

ImmutableSpaceship enterprise = new ImmutableSpaceship("Enterprise");enterprise.exploreGalaxy();

How can we change this unchangeable spaceship? How can we explore strange new worlds and “boldly go where no man has gone before”?

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }

public final class ImmutableSpaceship { private final String name; private final Destination destination; public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

What is an Immutable?

As it turns out, we can’t. As I've said, you cannot change an Immutable.

Instead, you can return a new Object that does reflect the change.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }

public final class ImmutableSpaceship { private final String name; private final Destination destination; public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

What is an Immutable?

In this case we’d return a new ImmutableSpaceship object with

a new Destination value of “OUTER_SPACE”.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Outline

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

So far this seems useless. Why should you bother with Immutables?

What kind of advantages will they bring you?

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Advantages of Immutables

• Are stable & fault tolerant

First of all, Immutable classes greatly reduce the effort needed to implement a stable

and fault tolerant system.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Advantages of Immutables

• Are stable & fault tolerant

After object creation, Immutables can be in only one state, which seems very confining at first,

but it’s actually extremely beneficial. Let’s see why.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

Imagine we have to implement a bank's accounting software.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

As a result of the financial crisis, the bank doesn't want its customers to be in debt.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

In other words, there is a business rule that

an account balance must never be negative. Such a rule is called an invariant.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

private void validate(long balance) { if (balance < 0) { throw new IllegalArgumentException("balance must not be negative:"+ balance); }}

To implement this rule, we will add a validation method that gets called

whenever the balance is changed.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

private void validate(long balance) { if (balance < 0) { throw new IllegalArgumentException("balance must not be negative:"+ balance); }}

Immutables are stable & fault tolerant

In case of an attempt to overdraw the account,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

private void validate(long balance) { if (balance < 0) { throw new IllegalArgumentException("balance must not be negative:"+ balance); }}

an IllegalArgumentException will be thrown.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

As you probably can imagine, the bank wants us to implement

a variety of functions for their clients,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

for example withdraw(), payDebt() and

transferMoney().

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]} To enforce the rule that the account’s

balance must never be negative, we have to call the validation method from all these

methods.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]}

This seems like a lot of duplicated code. There must be a better way!

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]} Pause here and think of an

alternative way to make sure that none of these methods would overdraw the account’s balance.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]}

Okay, the truth is, I tricked you a bit. We don't actually need to validate the balance in each

method.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]}

I said we need to validate the object whenever it is changing,

but an Immutable is not changing.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]}

Immutables are stable & fault tolerant

Instead, we validate the balance once in the constructor, so that no invalid object can be constructed.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]} Once validated,

an immutable object will stay valid for its entire lifetime.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]} WOW! This is really cool!

Methods like withdraw(), payDebt() and transferMoney() will return a new object, which will again call the constructor and validate the new balance.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) {…}

public ImmutableAccount payDebt(long amount) {…}

public ImmutableAccount transferMoney(long amount) {…}

[…]}

Immutables are stable & fault tolerant

But wait, it gets even better! An Immutable remains consistent – even in the case of an exception.

Let me give you an example:

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

Imagine you go to the ATM -

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

- to get some cash.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

You put in your bank card, you type in your PIN.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

Balance:

+20,000.00

The bank takes the money …

Copyright © 2016 Marcus Bielwww.marcus-biel.com

0.00Balance:

Immutables are stable & fault tolerant

out of your account. But just before it gets into your hands,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

there’s an issue with the ATM. The money has already been taken out of your bank

account, but it isn’t coming out of the machine.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

0.00Balance: So now, you can kiss your money good bye.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

0.00Balance:

Unless the account has been implemented as an Immutable.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

Balance:

+20,000.00

In this case, your balance will be in the same state that it was before the failure occurred. Let’s see what this looks like in code.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) { long newBalance = newBalance(amount); return new ImmutableAccount(newBalance); }

private long newBalance(long amount) { }[…]}

Immutables are stable & fault tolerant

If we are trying to withdraw money from our ImmutableAccount class,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables are stable & fault tolerant

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) { long newBalance = newBalance(amount); return new ImmutableAccount(newBalance); }

private long newBalance(long amount) { // exception during balance calculation

}[…]}

and an exception occurs,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) { long newBalance = newBalance(amount); return new ImmutableAccount(newBalance); }

private long newBalance(long amount) { // exception during balance calculation

}[…]}

Immutables are stable & fault tolerant

a new ImmutableAccount object will never be created and

the original bank account object will stay unchanged and be saved.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) { long newBalance = newBalance(amount); return new ImmutableAccount(newBalance); }

private long newBalance(long amount) { // exception during balance calculation

}[…]}

Immutables are stable & fault tolerant

So as I’ve shown you, an Immutable object can never get into an inconsistent

state, even in the case of an exception.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) { long newBalance = newBalance(amount); return new ImmutableAccount(newBalance); }

private long newBalance(long amount) { // exception during balance calculation

}[…]}

Immutables are stable & fault tolerant

This stability comes at no cost, apart from the cost of the initial validation.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) { long newBalance = newBalance(amount); return new ImmutableAccount(newBalance); }

private long newBalance(long amount) { // exception during balance calculation

}[…]}

Immutables are stable & fault tolerant

It's based on the simple fact that an Immutable cannot change after object creation.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableAccount {

private final long balance;

public ImmutableAccount(long balance) { validate(balance); this.balance = balance; }

public ImmutableAccount withdraw(long amount) { long newBalance = newBalance(amount); return new ImmutableAccount(newBalance); }

private long newBalance(long amount) { // exception during balance calculation

}[…]}

Immutables are stable & fault tolerant

Ok, I hope you haven't fallen asleep yet. There is so much more that Immutables have to offer,

so let’s go on.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables can be shared freely

• Are stable & fault tolerant• Can be shared freely

Since Immutables don’t change, they can be shared freely. Let’s see what this means.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables can be shared freely

Balance

AccountAccount

Holder HolderBalance

In this example, two Mutable Account objects are

sharing the same Balance attribute.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables can be shared freely

AccountAccount

Holder HolderBalance

If the Account object on the right

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables can be shared freely

AccountAccount

Holder HolderBalance

changes the balance, this will also indirectly influence the Account object on

the left.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables can be shared freely

AccountAccount

Holder HolderBalance

If, however, the balance attribute is immutable,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Holder

Account

Immutables can be shared freely

Account

HolderBalanceBalance

when the Account object on the right tries to change the balance object, it will not change,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Account

Balance Holder

Immutables can be shared freely

Account

Holder Balance

but return a new object instead. So there will be a second balance object now.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Account

Balance Holder

Immutables can be shared freely

Account

Holder Balance

For the same reason - an Immutable does not need a copy constructor when copying an object.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables can be shared freely

If you don’t understand what this means or you’d like to learn more about cloning and copy constructors,

check out my video “Shallow versus Deep Copy”.

http://www.marcus-biel.com/shallow-vs-deep-copy-video-tutorial/

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables can be shared freely

• Are stable & fault tolerant• Can be shared freely

Immutables can even be shared freely, when using a lock free algorithm in

a multithreaded environment, where multiple actions happen in parallel.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables can be shared freely

• Are stable & fault tolerant• Can be shared freely

Many see this as the key benefit of Immutables. However, it is a very advanced subject,

so I won't go into detail here, but will probably show it at a later stage.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables work well as Map keys and Set elements

• Are stable & fault tolerant• Can be shared freely• Work well as Map keys and Set

elements

Finally, Immutable objects are also a perfect option to use as Map keys and Set elements,

since Map keys and Set elements must never change.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables work well as Map keys and Set elements

These are the main advantages of Immutables. Let’s also look at their disadvantages.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Disadvantages of Immutables

• May lead to performance problems

The biggest disadvantage of Immutable classes is that their use may lead to performance problems.

Let's see how.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables may lead to performance problems

Object

Immutables require a new object

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables may lead to performance problems

for every distinct state they represent.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables may lead to performance problems

Therefore, the use of Immutables often increases the number of objects created.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables may lead to performance problems

Naturally, the more objects that are created, the more system resources will be used.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Immutables may lead to performance problems

However, this may not be a problem at all. There are many more influencing factors

as we will see later on.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

How to create an Immutable

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

So now that I’ve shown the value of an Immutable class. How can we actually make one?

Copyright © 2016 Marcus Bielwww.marcus-biel.com

How to create an Immutable

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

To make a class immutable, we have to follow a few rules:

Copyright © 2016 Marcus Bielwww.marcus-biel.com

1. Make all attributes private final

1.Make all attributes private final.

First of all, we have to make all its attributes private and final

Copyright © 2016 Marcus Bielwww.marcus-biel.com

private final String name; private final Destination destination;

1. Make all attributes private final

public final class ImmutableSpaceship {

public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; } public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }[…]}

Let’s illustrate this by looking at the ImmutableSpaceship class I introduced you to before.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

1. Make all attributes private final

private final String name; private final Destination destination;

public final class ImmutableSpaceship {

public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; } public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }[…]}

We make the attributes private, so that no reference can be accessed from outside.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

1. Make all attributes private final

private final String name; private final Destination destination;

public final class ImmutableSpaceship {

public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; } public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }[…]} While private variables cannot be

accessed from outside the class, they can still be reassigned.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

1. Make all attributes private final

private final String name; private final Destination destination;

public final class ImmutableSpaceship {

public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; } public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }[…]}

To prevent this we also have to make all variables final.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

1. Make all attributes private final

private final String name; private final Destination destination;

public final class ImmutableSpaceship {

public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; } public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }[…]}Setting all internal reference variables to final –

clearly communicates our intent to make an immutable class.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

1. Make all attributes private final

private final String name; private final Destination destination;

public final class ImmutableSpaceship {

public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; } public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }[…]}

Should someone try to reassign a reference variable, a compiler error will occur.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

2. Don’t provide any methods that modify the object’s state

1.Make all attributes private and final.2.Don’t provide any methods that modify

the object’s state.

Okay. Second, we must not provide any methods

that modify the object’s state.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

2. Don’t provide any methods that modify the object’s state

1.Make all attributes private and final.2.Don’t provide any methods that modify

the object’s state.

This I have already briefly discussed at the beginning of this presentation, but now we will look at it more closely.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }

2. Don’t provide any methods that modify the object’s state

public final class ImmutableSpaceship { private final String name; private final Destination destination; public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

For any change that you want to apply to your Immutable object,

you have to provide a method that returns a new object.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

2. Don’t provide any methods that modify the object’s state

public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }

public final class ImmutableSpaceship { private final String name; private final Destination destination; public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}Attributes that do not change, like “name” in this case,

can be copied from our current object.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

2. Don’t provide any methods that modify the object’s state

public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }

public final class ImmutableSpaceship { private final String name; private final Destination destination; public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

Attributes that do change, like “destination” in this case, have to be initialized with a new value instead.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

3. Ensure that the class can’t be extended

1.Make all attributes private and final.2.Don’t provide any methods that modify

the object’s state.3.Ensure that the class can’t be extended.

Let’s go on to the next rule. To further protect our class from being changed, we also have to prevent it from being extended.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

3. Ensure that the class can’t be extended

1.Make all attributes private and final.2.Don’t provide any methods that modify

the object’s state.3.Ensure that the class can’t be extended.

Extending a class would allow you to override its methods.

This would allow you to directly change the “unchangeable" object.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

3. Ensure that the class can’t be extended

1.Make all attributes private and final.2.Don’t provide any methods that modify

the object’s state.3.Ensure that the class can’t be extended.

Let's look at a code example to better illustrate this:

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public class RomulanSpaceship extends ImmutableSpaceship {

@Override public RomulanSpaceship exploreGalaxy() { this.destination = Destination.OUTER_SPACE; return this; }

3. Ensure that the class can’t be extended

[…]}

private String name; private Destination destination;

public RomulanSpaceship(String name) { super(name); }

So here we have a RomulanSpaceship extending our ImmutableSpaceship.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

@Override public RomulanSpaceship exploreGalaxy() { this.destination = Destination.NEUTRAL_ZONE; return this; }

public class RomulanSpaceship extends ImmutableSpaceship {

3. Ensure that the class can’t be extended

[…]}

private String name; private Destination destination;

public RomulanSpaceship(String name) { super(name); }

Its overridden exploreGalaxy() method violates the rules of an Immutable,

as it directly changes the destination attribute.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

ImmutableSpaceship immutableSpaceship = new RomulanSpaceship("Battlequeen");

3. Ensure that the class can’t be extended

As RomulanSpaceship extends ImmutableSpaceship

Copyright © 2016 Marcus Bielwww.marcus-biel.com

3. Ensure that the class can’t be extended

ImmutableSpaceship immutableSpaceship = new RomulanSpaceship("Battlequeen");

we can create an instance of a RomulanSpaceship,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

3. Ensure that the class can’t be extended

ImmutableSpaceship immutableSpaceship = new RomulanSpaceship("Battlequeen");

and assign it to an ImmutableSpaceship reference variable.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

ImmutableSpaceship immutableSpaceship = new RomulanSpaceship("Battlequeen");[…]immutableSpaceship.exploreGalaxy(); // internally changes the "immutable" Spaceship

3. Ensure that the class can’t be extended

Much later in the code, in a different class and method, we will call the exploreGalaxy() method on our ImmutableSpaceship instance -

Copyright © 2016 Marcus Bielwww.marcus-biel.com

ImmutableSpaceship immutableSpaceship = new RomulanSpaceship("Battlequeen");[…]immutableSpaceship.exploreGalaxy(); // internally changes the "immutable" Spaceship

3. Ensure that the class can’t be extended

which, much to our concern, will internally change the spaceship instance,

which we expected to be unchangeable.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public final class ImmutableSpaceship {

3. Ensure that the class can’t be extended

private final String name; private final Destination destination; public ImmutableSpaceship(String name) { this.name = name; this.destination = Destination.NONE; } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; } public ImmutableSpaceship exploreGalaxy() { return new ImmutableSpaceship(name, Destination.OUTER_SPACE); }[…]}To prevent this, we just have to make our class final.

A final class can’t be extended, so it won’t be possible to override any method either.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

1.Make all attributes private and final.2.Don’t provide any methods that modify the

object’s state.3.Ensure that the class can’t be extended.4.Ensure exclusive access to any mutable

attributes.And now to the final rule – we have ensure exclusive access to any mutable

attributes.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Here you can see a representation of our spaceship object.

Name

Spaceship

DestinationName

Immutable

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

The attribute “name” is of type String, which is an Immutable.

Name

Spaceship

DestinationName

Immutable

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

As I've already shown you, you can freely share Immutable attributes -

Name

Spaceship

DestinationName

Immutable

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Name

Spaceship

DestinationName

Immutable

Mutable

with other objects, as they cannot be changed.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Spaceship

DestinationName

Immutable

The Destination object, in this case, we’ll assume, is Mutable.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Spaceship

DestinationName

Immutable

Mutable

Anyone who holds a reference to it -

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Spaceship

DestinationName

Immutable

Mutable

can alter it.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Immutable

Mutable

This will effectively alter our "Immutable" object.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

Mutable

4. Ensure exclusive access to any mutable attributes

In other words, it would not be immutable.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Mutable

So to protect our Immutable object -

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Mutable

Spaceship

DestinationName

Immutable

we have to isolate the mutable destination attribute from the outside and prevent anyone from getting hold of it.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Spaceship

DestinationName

Immutable

Destination

MutableTo achieve this, we never obtain or return a direct reference to a destination object. Instead we create a deep copy and work with that

instead.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Spaceship

DestinationName

Immutable

DestinationDestination

MutableAs long as the mutable destination object

is never directly shared,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Spaceship

DestinationName

Immutable

DestinationDestination

Mutablea change inside an external object will not have any effect on our immutable object.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

Spaceship

DestinationName

Immutable

DestinationDestination

Mutable

Okay, talk is cheap, show me the code.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return destination; }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); }

4. Ensure exclusive access to any mutable attributes

private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

To ensure exclusive access to our mutable destination attribute,

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return destination; }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

we have to check all public methods and constructors for any

incoming or outgoing Destination references.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return destination; }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

Let’s do this now.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return destination; }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

The public constructor does not receive any Destination reference.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return destination; }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

The Destination object it creates is safe, as it cannot be accessed from outside.

So the public constructor is good as it is.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return destination; }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

The public currentDestination() method returns a reference -

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return destination; }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

to our internal Destination object, so this must be fixed.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return new Destination(destination); }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

Now, instead of returning the real reference we create a deep copy

of our Destination object and return a reference to the copy instead.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return new Destination(destination); }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

Finally, the public newDestination() method receives -

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return new Destination(destination); }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

a Destination reference -

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return new Destination(destination); }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

and forwards this reference to our private constructor.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return new Destination(destination); }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

Now the private constructor directly stores the mutable Destination reference it receives.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return new Destination(destination); }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

So, by following the execution path, we found that it is directly stored in the private

constructor.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return new Destination(destination); }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = destination; }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

This must not be allowed.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

4. Ensure exclusive access to any mutable attributes

public ImmutableSpaceship newDestination(Destination newDestination) { return new ImmutableSpaceship(this.name, newDestination); }

public Destination currentDestination() { return new Destination(destination); }

public ImmutableSpaceship(String name) { this.name = name; this.destination = new Destination("NONE"); } private ImmutableSpaceship(String name, Destination destination) { this.name = name; this.destination = new Destination(destination); }

[…]}

public final class ImmutableSpaceship { private final String name; private final Destination destination;

To stop it immediately, we store a reference to a deep copy of the external Destination object.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

• What is an Immutable?• Advantages & disadvantages• How to create an Immutable• When to use Immutables

Okay. So I've shown you what an Immutable is, I've told you about its advantages and disadvantages,

and finally, I have demonstrated how to create an Immutable class.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

There is just one last thing I would like to tell you –

When should YOU actually use an Immutable class in your code?

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

The question of whether you should design a specific class as an Immutable depends mainly on whether the performance of the

overall system is sufficient or not.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

This again depends on the nature of the system and all

aspects related to it. For example: What kind of

specific problem are you trying to solve?

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

On what kind of hardware is your program running? Is it a desktop

or web application? It also depends on the internal structure of your code.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

For example: Of how many packages, classes and methods does your code consist of? As you can see, there is no simple answer to this very complex

question.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

Each case must be looked at individually.

As a general recommendation however,

I advise you to follow this approach:

Focus on designing a system that uses

immutables to the greatest possible extent.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

Facilitate their use by designing simple

classes with few attributes and methods.

Immutables may become a burden

when they are too complex. Simplicity is key.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

In this endeavor, Clean Code and Immutables are a well matched pair, reinforcing each other.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

In the majority of cases, this approach will lead to a

system that exceeds all requirements.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

If however, testing reveals that you have not achieved

satisfactory performance, relax the immutability rules gradually.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

As much as necessary, but as little as possible.

Copyright © 2016 Marcus Bielwww.marcus-biel.com

When to use Immutables

Copyright © 2016 Marcus Biel

All rights reserved.

top related