We can also generate completely different behavior by passing in a different lambda expres-
sion. For example, in Example 8-41 we're creating a unique identifier for each Java thread
that is sequential.
Example 8-41. A ThreadLocal identifier
AtomicInteger threadId = new
new AtomicInteger ();
ThreadLocal < Integer > localId
= ThreadLocal . withInitial (() -> threadId . getAndIncrement ());
int idForThisThread = localId . get ();
Another interpretation of the open/closed principle that doesn't follow in the traditional vein
is the idea that immutable objects implement the open/closed principle. An immutable object
is one that can't be modified after it is created.
The term “immutability” can have two potential interpretations: observable immutability or
implementation immutability . Observable immutability means that from the perspective of
any other object, a class is immutable; implementation immutability means that the object
never mutates. Implementation immutability implies observable immutability, but the inverse
isn't necessarily true.
A good example of a class that proclaims its immutability but actually is only observably im-
mutable is java.lang.String , as it caches the hash code that it computes the first time its
hashCode method is called. This is entirely safe from the perspective of other classes be-
cause there's no way for them to observe the difference between it being computed in the
constructor every time or cached.
I mention immutable objects in the context of a topic on lambda expressions because they are
a fairly familiar concept within functional programming, which is the same area that lambda
expressions have come from. They naturally fit into the style of programming that I'm talk-
ing about in this topic.
Immutable objects implement the open/closed principle in the sense that because their intern-
al state can't be modified, it's safe to add new methods to them. The new methods can't alter
the internal state of the object, so they are closed for modification, but they are adding beha-
vior, so they are open to extension. Of course, you still need to be careful in order to avoid
modifying state elsewhere in your program.
Immutable objects are also of particular interest because they are inherently thread-safe.
There is no internal state to mutate, so they can be shared between different threads.