Null Object
Something for Nothing
Kevlin Henney
March 2003
Kevlin@curbralan.com
Kevlin@acm.org
Abstract
The intent of a null Object is to encapsulate the Absence of an Object by providing a
Substitutable Alternative That Offers Suitable Default Do Nothing Behavior. in Short, A Design
Where "Nothing Will Come Of Nothing" [shakespeare1605].
Null Object Is A Tactical Pattern That Has Been Discovered Time and Again, And Not Only in
Object-Oriented Systems: Null File Devices (/ dev / null on unix Nul on Microsoft Systems),
NO-OP MACHINE INSTRUCTIONS, TERMINATORS ON Ethernet Cables, ETC.
THE PATTERN HAS BEEN DOCUMENTED IN A Variety of Forms by Many Authors, Varying Widely in
Structure and length: from a thorough and structured gof-like form [woolf1998] to a brief
Thumbnail-like production-rule form [henney1997]. this paper is deived from A
Previously Published Article [Henney1999] and incrudes the aforementioned thumbnail.
THE AIM OF THE CURRENT WORK Is To Update and Capture The Latest Understanding of The
Pattern and ITS Implications, Also Addressing A Wide Audience by Documenting The Pattern
Primarily with respect to java and uml.
Null Object
2 of 10
Thumbnail
IF
.. an Object Reference May Be Optionally Null and
.. this Reference Must Be Checked Before Every Use and
.. The result of a null check is to do nothing or assocign a suitable default value
THEN
.. provide a class deact from the object reason's type and
.. Implement All Its Methods To Do Not, or Provide Default Results and
.. Use an instance of this class WHENEVER THE Object Reference Would Have Been Null
Problem
Given That An Object Reference May Be Optionally Null, And That The Result of A Null Check IS
To do nothing or us, how can the Absence of an object - the PresenceOf a Null Reference - Be Treated Transparently?
EXAMPLE
Consider a logging facility for some kind of simple server-housed service. It can be used to
Record Exceptional Events, Housekeeping Activities, And The Outcome of Operations During
The Course of the Service's Operation. One Can Imagine Many Different Kinds of Log, Such AS
A log that Writes Directly to the console or one this uses rmi to send a message to a remote
Logging Server. However, a Server Is Not Necessarily Required To Use A Log, So The Association
Between the Server and the log is optional. Figure 1 shows The Relationships diagrammed in
UML, AND Listing 1 Shows The Log Interface and Two Simple Implementations.
Figure 1. UML Class Diagram of a service with optional support for logging.
Public Interface log
{
Void Write (String Messagetolog);
}
Public Class Consielog Implements LOG
{
Public void write (String MessageTolog)
{
System.out.println (Messagetolog);
}
}
.interface.
Log log
0..1
Service
File
Log
Console
Log
Null Object
3 of 10
Public Class Filelog Implements Log
{
Public Filelog (String logfilename)
{
Try
{
OUT = New FileWriter (LogfileName, True);
}
Catch (IOException Caught)
{
Throw new runtimeException ("Failed to Open Log File:" caught);
}
}
Public void write (String MessageTolog)
{
Try
{
Out.write ("[" new date () "]" messagetolog "/ n");
Out.flush ();
}
Catch (IOException Caught)
{
Throw New RuntimeException ("Failed to Write to Log:" CAUGHT);
}
}
PRIVATE FINAL FILEWRITER OUT
}
Listing 1. THE ROOT LOG Interface and Sample Concrete Implementations.in LISTING 2, IT CAN BEEN THAT BECAUSE THE OPTION EXSTS for Not Having Logging Enabled for
A Service, a Check Against Null Is Required Before Every Use of log.
Public Class Service
{
Public service ()
{
this (null);
}
Public service (log log)
{
THIS.LOG = Log;
... // Other Initialization
}
Public Result Handle (Request Request)
{
IF (log! = null)
Log.Write ("Request" Request "Received");
...
IF (log! = null)
Log.write ("Request" Request "Handled");
...
}
... // Other Methods and Fields
PRIVATE LOG LOG;
}
Listing 2. INITIALIZING AND Using A Log Object in The Service.
Null Object
4 of 10
FORCES
There Is A Great Deal of Procedural Clunkiness In Code Such AS
IF (log! = null)
Log.Write (MESSAGE);
This Style Is Repetitive As Well As Error Prone: Reference CHECKS for Null References Can Clutter
And Obfuscate Code; it is to easy to forget to write the null guard. however, the user is
Required to Detect The Condition and Take Appropriate Inaction, Even Though The Condition
Is Not in Any Way Exceptional - Having a Null Log Is A Normal and Expected State of The
Relationship. The Condition Makes The Use of the Logging Facility Less Uniform.
A feature of conditional code is the explicitness of its conditions and the visibility of there
Resulting Control Flow. However, this is only a benefitiffiff f The decisions taken isportant
To the logic of the surrounding code, Otherwise the resulting code is less Than
More - Direct. Such Minor But Essential Decisions Become Distractions Rather Than
Attractions, Obscuring The Core Algorithm.
WHERE CONDITIONAL COGIC, MAKING THE Method. This
Is Especially True If The Code Is Repeated Frequently, As One Might Expect from The Logging
Facility In the Example, or if in-house coding guidelines encourage the use of blocks to
Surround Single Statements:
IF (log! = null)
{
Log.Write (MESSAGE);
}
The use of an expedition Conditional Means That The User May Choose ALTERNATIVE ACTIONS To SUIT
The context. howeever, if The action is always the size and if the optional rellationship is
FREQUENTLY Used, As One Might Expect of Logging, IT Leads to Duplication of The Condition and
ITS Action. duplicate code is considered to have a "bad smell" [fowler1999]. duplication
Works against Simple Changes, Such As Fixes or Improvements, and is in violation of the
Dry PrinciPle (Don't review yourself) [Hunt 2000].
For An Explicit Conditional On A Null Reference The Cost of Execution Amounts To no more
THAN A TEST AND A Branch. on the other of an expedition Test Means That there Will
ALWAYS Be a test. Because this test is used in Separate PIECES OF CODE IS NOT PIECES OF CODE IS NOT PIECLE TO
Set Debugging Breakpoints, or Introduce Diagnostic Statements, Consistently for All Uses of
The Null Case.
The Code Would Be Much Cleareer If The Null Tests Could Be tent or hidden. The jvm
Already Checks Each Access Via Any Reference Against Null, And There Can Be a Temptation To
Exploit this behavior (See Listing 3). This Technique is Specific To Languages That Guarantee
That All Accesses Are Checked, E.G. Java and C #, and Will Lead to undesirable (undefined)
Results where this Guarantee IS ABSENT, E.G. C . Null Object
5 of 10
Public Class Service
{
...
Public Result Handle (Request Request)
{
Try
{
Log.Write ("Request" Request "Received");
...
Log.write ("Request" Request "Handled");
...
}
Catch (NullPointersRexception Ignored)
{
}
}
...
}
Listing 3. Assuming a non-null log and ignoring any nullpointerserexception.
There Are Two Objections to Such Piggybacking. There Is The Matter Of Style and Taste, AS
Well as the cost of overgetness at the expense of correctness:
.. style: in spite of the vagueness of the commit advice That "Exceptions Should Be
Exceptional ", The Reliance ON NullpointersReption for Masking the Absence of Logging
Does Seem to be a clear abuse of what is otherwise a hollow place gratitude. The Normal
Motivation for Adopting Such A Style Is as A Performance Micro-Optimization; Such
Reasoning does Not Apply to Listing 3.
.. Correctness: a Nullpointers: a NullPointers: a NullPointers: Via Null, And Not Just
Writing through log. Ignoring Such Exceptions Runs The Obvious Risk of Quashing
Genuine Errors, throwing the baby out with the bath water. To check log against null in
The catch clause further uglifies the code, And Still Does Not Offer a Guarantee in All Cases
That a null log was the culprit.
What is needed of a solution is The Ability to wish Away the Null So That Nothing - Rather
Than Something Exceptional - Happens. The Solution Should Be Non-Intrusive, Easy To
Code, and inexpensive at runtime.
Solution
PROVIDE SOMETHING for NOTING: a class this conforms to the interface required of the object
Reference, implementing all of its methods to do not not return suitable defaultvalues. Use an instance of this class when the object reference 10 otherwise has
Null. Figure 2 Shows An Essential, Typical Null Object Configuration AS Class Model. Other
Expressions of this Pattern is, of course, possible.
A null Object Can Be Used to Complete Many Other Common Patterns and Object
Structures: a Null Iterator [Gamma 1995] Goes Nowhere; a Null Command [Gamma 1995]
Does (and undoes) Nothing; a Pointer to an Empty Function Can Be Used to Provide Null
Callback Behavior In C; A Null Collection Is Empty and Cannot Be Changed; A Null Strategy
[Gamma 1995] Province no algorithmic behavior, a generalization That Extends to Compiletime
Binding of Template Policies IN C , E.G. Non-Locking Behavior for Strategized
Locking in a Single-Threaded ENVIRONMENT [SCHMIDT 2000]; A Null Lamina Can Terminate
Layers [Buschmann 1996], Such As a Null Socket Layer for A Standalone Workstation.
Null Object
6 of 10
A Null Object SHOULD NOT BE Used Indiscriminately As a Replacement for Null References. ITS
INTENT is to encapsulate the Absence of an Object Where That ABSENCE IS Not Profoundly
Significant to the user of an actual object. if The OptionAlity Has Fundamental Meaning That
Leads to Different Behavior, a Null Object Would Be An INAPPRIAT. Any NEED for A
Runtime Type Query, Such As An Isnull Method, Indicates That Absence IS Significant Rather
.
For Example, In A Graphical Editor, A Null Fill Color Leads to Transparency and Would Be A
Good use of a null object. However, The State of Being Unmarried Is Not Best Reperesentedwith A Null Spouse Object: Marriage IS Optional, And Being Single Really Is Different.
Figure 2. KEY ROLES IN A Typical Null Object Collaboration.
Resolution
Returning to the Server-logging Example, a Null Object Class, Nulllog, Can BE Introduces
INTO The log hierarchy. Such a comfortably null class (see listing 4) does nothing and does
Not Demand A Great DEAL OF CODING SKILL!
Public Class Nulllog IMPLEMENTS LOG
{
Public void write (String MessageTolog)
{
}
}
Listing 4. a Nulllog Class Providing do Nothing Behavior.
THE TACTICAL BENEFIT OF A NULL Object, Once Initialized, IS in Simplifying The Use of this
Simple logging framework. it is now guarance That The Relationship to a log Object IS
MANDATORY, I.E. The Multiplicity from the service to the log is 1 rather Than 0..1. this
Strengened rellationship allows the expeneit conditional code to be eliminated, MAKING
Logging Simpler and More Uniform. Polymorphism Takes Up The Responsibility for Selection,
Making The Presence (or Absence) of Logging Transparent (See Listing 5).
.interface.
Interface
1
Client
Actual
Object
NULL
Object
Method
Method Method Do Not Nothing
Null Object
7 of 10
Public Class Service
{
Public service ()
{
This (new nulllog ());
}
Public service (log log)
{
THIS.LOG = Log;
...
}
Public Result Handle (Request Request)
{
Log.Write ("Request" Request "Received");
...
Log.write ("Request" Request "Handled");
...
}
...
PRIVATE LOG LOG;
}
Listing 5. Introducing a Null Object Into Service.
Figure 3 Shows The Classes and Interfaces in The Design (Based on Listing 4, Listing 5, Andadditional Classes from Figure 1) Andhow Correspond, in Terms of Roles, To The
Elements Outlined in Figure 2.
Figure 3. The Relationship Between The Problem Resolution and The Roles Described in Figure 2.
Consequences
Introducing a Null Object Simplifies The Client's Code by Eliminating Superfluous and SUPERFLUOS
REPEATED CONDITIONALS THATER NOT PART OF A METHOD'S CORE LOGIC. Selection and Variation Are
Expressed THROUGH POLYMORPHISM AND inheritance Rather Than Procedural Condition
Testing. Taking a Step Back, Polymorphism Can Be Seen to Magic Away Switch Statements OR
IF Else if Cascades. in The Specific Case of Null Object, The Missing (But Implied) EMPTY
Default or else Has been Captured and Concealed.
Service
File
Log
Console
Log
Log
NULL
Log
Nullobject
Client Interface
Actual
Object
Actual
Object
NULL
Object
Null Object
8 of 10
The Object Relationship Moves from Being Optional To Mandatory, Making The Use of the Of THE
Relationship More Uniform. However, To Preserve this Invariant, Care Must Be Taken To
Ensure That The Reference Is Never Seen As a Null:
.. The Reference May Be Decilad Final So That Only The Initialization Is Required To Guard
Against a Null Reference, Setting A Null Object In Its Place.
.. Alternative, ONLY Indirect Variable Access [Beck1997] Should Be Used to Access To
Reference. a setting method [beck1997] can Ensure That The Reference IS Assigned A
Null Object Rather Than A Null Reference, or a getting method [beck1997] can Ense
That a Null Reference Is Returned As a Null Object.
A null object is encapsulated and cohesive: it does one thing - Nothing - And It Does IT
Well. this Reification of the Void and Encapsulation of Emptiness Eliminates Duplicate
Coding, Makes The (Absence of) Behavior Easier To Use, And Provides a Suitable Venue for
Debug Breakpoints or Print Statements.
The Absence of Any Side Effects on a Null Object Means That Instances Are Immutable, And
AreateFore Shareable and Intrinsically Thread Safe. A Null Object Is Typically Stateless
And ITENTINTITY IS NOT A SIGNIFICANT Part of Its Make Up, Which Means That All Instances Are
Equivalent. if a time or space optimization is required a single static instance, but not
Necessarily A Singleton Object [Gamma 1995], May BE Used in Place of Freshly Instantiated
Null Objects.
On The Other Hand, Using A NULL OBJECT IN A RELATIONSHIP Means That Method Calls Will
Always Be Executed and Their Arguments Will Always Be Evaluated. for The Common Case
This Is Not a Problem, But There Will Always Be An Identifiable Overhead for Method Calls
Whose Argument Evaluation IS Complex and Expensive.
The Use of Null Object Does Not Scale To Remote Objects. If A Java Null Object WERE TO
Implement java.rmi.remote, EveryMeth Call Would Incur The Overhead of a Remote Call
And Introduce A Potential Point of Failure, Both of Which Wouldh wouldh wouldh wouldering
Basic do nothing behavior. Therefore, if used in a distributed context, Either Null Should Be
Passed in Preference To a null Object or the null Object shouth be passed by copy. in A
Distributed Environment Transparent Replication Rather Than Transparent Sharing Becomes
For RMI this Does Not Introduce A Significant Overhead, Because A NULL OBJECT
Class Is Small and Loading It Will Be Relatively Cheap. The Only Change To The Code IS To
Ensure That the Null Object Class Implements Java.io.Serializable: Public Class Nulllog Implements Log, Serializable
{
...
}
Users of a hierarchy That Includes a Null Object Class Will Have More Classes To Take ON
Board. The beneftion of the point of create, explicit knowledge of create
The New Null Object Class is Not needed. where there is man waiting,
More Null Object Classes Can Be Introducesd. A Variation ON this theme is the use of an
Exceptional Value Object [Cunningham1995]. Rather Than Doing Nothing When a Method
IS Called, An Exceptional Value Either Raises An Exception Or Returns A Further
Exceptional value. A generalization of this theme is the special case [fowler2003],
WHERE An Object In Some Way Repesents a Special Case, Such as an Exceptional Value ORUE OR A
Null Object, Each of Which Can Be Considered Special Cases of Special Case.
THE IMPLEMENTATION OF Do Nothing Behavior Is Simple for Methods: EMPTY METHOD
Bodies. However, Methods That Return Results Can Only Avoid The INEVITABLE RETURN
Null Object
9 of 10
Statement by throwing an exception - Behavior More Appropriate for An Exceptional
Value Than for a Null Object. Different Parameter Passing Modes Require Different
Responses:
.. in arguments: arguments passed to the method to provide it with suitable information
Can Be Safely Ignored, Requiring No Handling Code in The Method Body. Pass by Copy IS
Java's Sole Mechanism for Passing Arguments. In Corba the in Mode Corresponds To
In C Pass by Copy and Pass by Const Reference Play THIS ROLE. In C # The
IN Mode Is The Default for Method Arguments.
.. void Result: no method code is required to deal with a void return type ... out arguments: an out argument virt, by definition, be set and so the method body
Must set it to an appropriate default. Java Does Not Support these Directly, But The THE
Holder IDiom is offen buy to emulate it. This can is buy in the mapping of corba's
Out arguments. in c # an out argument must also be set.
.. Non-Void Result: As with out arguments, an appropriate default must be returned.
.. in-out arguments: an in-out argument may be each either ignored, as with an an in argument,
Or set to an appropriate default, as with an out argument. Java Only Supports in-Out
Arguments Via the Holder IDiom, As Found in The Mapping of Corba's Inout
Arguments. The Corresponding Feature IN C is pass by reference. in c # Ref
Arguments Fulfil this role.
However, what precisely is meant by "appropriate default"?
.. Success Defaults: a success value is offen an identity value of some kind and does not
Indicate Any Form Of Failure, And Will Typically Not Affect The Caller. For Numeric Types, 0
IS OFTEN Such a Value. For Result Objects That Represent Values, A Null Reference IS
Sometimes Suitable, But More offten a Default Constructed Object IS A Better Result, E.g. ""
As opposed to null for a string. For Result Objects That Repesent Behavior, Either a Null
OR a NULL Object of The Result Type Should Be Returned.
.. Failure Defaults: a Failure Value Shows That A Method Call Was in Some Way
Unsuccessful, But in The Context of Null Object It Should Probably Not Be Fatal. for
Integer Types, -1 is Offen Used to Signal Failure. For floating point type, nan or infinity
Are The Common Out-of-Band Results. For Objects, Either A Null Reference or Anexceptional Value Should Be Returned.
IF no defaults area required - E.g. a method taking no arguments or in arguments only and
Returning void - Or Results Can Be Default Constructed - E.g. a returnofa of 0 for A
Numeric OR a NULL for a Reference - a Dynamic Proxy Can Be Used As a Generalized NULL
Object. Dynamic PROXIES Are A JDK 1.3 Feature (java.lang.reflect.Proxy) and, based on
Reflection, They Can Interpret Arbitrary Messages. A Null Object Dynamic Proxy Would
SIMPLY Discard All Method Requests, Returning Default Values Where Necessary.
Taking an existing application of code trias not useful object and modify it to do so
May Also Open the dor to bugs. by Following Carefully the Introducture Null Object
Refactoring [Fowler1999] Programmers Can Have Greater Confidence Making Such Changes
And Avoiding Pitfalls.
WHEN Introducing a Null Object Class Into An EXISTING SYSTEM A SuiTable Base Interface
May Not Exist for the Null Object Class to Implement. Either An Extract Interface
Refactoring [Fowler1999] Should Be Applied to Introduce One or The Null Object Class Must
Subclass the concrete class referred to by the reference. The second option allow becom
Unavoidable if the hierarchy code cannot Be Rearrany Code Cannot Be Rearrani
Option: IT Implies That Any Reperesentation In The Superclass Will BE IGNORED. SUCH
Inheritance with cancellation can list to code what is harder to understand Because the