Java create null object

How to create Null Object Pattern in Java

In Null Object Pattern a null object replaces the check of NULL object instance. This is useful when you don’t want to have null objects, but instead you need an object with default values.

Implementation

  • one class will define the real objects
  • the second class will define the Null Object used in case a real object is not define.

Will pick the example with a simple model interface.

package com.admfactory.pattern; public interface Model

The implementation for the real object.

package com.admfactory.pattern; public class User implements Model < private int id; private String name; public User(int id, String name) < this.id = id; this.name = name; >@Override public int getId() < return id; >@Override public String getName() < return name; >@Override public String toString() < return String.format("[id:%d,name:%s]", getId(), getName()); >> 

The implementation for the Null Object.

package com.admfactory.pattern; public class NullUser implements Model < @Override public int getId() < return 0; >@Override public String getName() < return "Null User"; >@Override public String toString() < return String.format("[id:%d,name:%s]", getId(), getName()); >> 

Also a factory class is needed to return the object if exists or instead to return a Null object.

To be more easier the factory class will create all the users and will store it in a local Hashtable. In real world this class will handle the database reading.

package com.admfactory.pattern; import java.util.Hashtable; public class UserFactory < private static Hashtableusers = new Hashtable(); static < Model u1 = new User(1, "John"); users.put(String.valueOf(u1.getId()), u1); Model u2 = new User(2, "Jan"); users.put(String.valueOf(u2.getId()), u2); Model u3 = new User(3, "Jose"); users.put(String.valueOf(u3.getId()), u3); >public static Model getUser(int id) < String key = String.valueOf(id); Model user = users.get(key); if (user == null) user = new NullUser(); return user; >> 

Example

Simple example using the Null Design Pattern implementation.

package com.admfactory.pattern; public class NullPatternExample < public static void main(String[] args) < Model u1 = UserFactory.getUser(1); Model u2 = UserFactory.getUser(2); Model u3 = UserFactory.getUser(3); Model u4 = UserFactory.getUser(4); Model u5 = UserFactory.getUser(5); System.out.println("Java Null Design Pattern Example"); System.out.println(); System.out.println(u1.toString()); System.out.println(u2.toString()); System.out.println(u3.toString()); System.out.println(u4.toString()); System.out.println(u5.toString()); >> 

Output

Java Null Design Pattern Example [id:1,name:John] [id:2,name:Jan] [id:3,name:Jose] [id:0,name:Null User] [id:0,name:Null User] 

You can notice that the u4 and u5 object are not present in the hashtable and an instantiation of Null object is return for these.

Источник

Null Object Pattern in Java

Join the DZone community and get the full member experience.

Today, I am discussing the less-used pattern called the null object pattern. In object-oriented programming, we deal very frequently with null objects. A null object refers to an object without any reference or an object defined with neutral/null functionality/behavior. These null objects need to be checked to ensure that they are not null while accessing any member or invoking any methods. This is because members or methods typically cannot be invoked on null objects.

Null Object Pattern

The null object design pattern describes the uses of null objects and their behavior in the system.

  • Null object patterns deal with null objects.
  • Instead of checking for the null object, we define null behavior or call do-nothing behavior.
  • These null objects can also be used to provide default behavior in case data is unavailable.
  • The advantage of this approach over a working default implementation is that a null object is very predictable and has no side effects — it does nothing.
  • The null object pattern can also be used to act as a stub for testing, in case a resource is unavailable for testing.
Читайте также:  Запаковать папку zip php

Before We Use the Null Object Pattern, We Should Understand:

  • This pattern should be used carefully. It can make bugs appear as a normal program execution.
  • We should not implement this pattern just to avoid null checks and make the code more readable. Actually, it is harder to read code that is moved to another place, like the null object class.
  • We have to perform additional testing to make sure that there is nowhere we have to assign a null instead of the null object.

Let’s take a look at an example to better understand this pattern.

Example of Null Objects

  • Create an abstract class (or interface) to specify various functionalities. I am using the shape interface for this example. Please note that I have created a method isNull() as well in the interface. It’s nice to have a method, and I like it because I can better identify and control null-defined objects. This method will return false for all of the concrete classes. And, it will return true only for the null object class.
package design.nullobject; public interface Shape < double area(); double perimeter(); void draw(); // nice to have method to indicate null object boolean isNull(); >
  • You will need to create a concrete class that extends this class or implements the interface). Each concrete class will define a specific version of the functionalities. I am defining three types of the shape: Circle , Rectangle , and Triangle . These concrete classes will define different types of shapes. Below is the code for the Circle class:
package design.nullobject; public class Circle implements Shape < // sides private final double radius; public Circle() < this(1.0d); >public Circle(double radius) < this.radius = radius; >@Override public double area() < // Area = π r^2 return Math.PI * Math.pow(radius, 2); >@Override public double perimeter() < // Perimeter = 2πr return 2 * Math.PI * radius; >@Override public void draw() < System.out.println("Drawing Circle with area: " + area() + " and perimeter: " + perimeter()); >@Override public boolean isNull() < return false; >>

Below is the code for the Rectangle class:

package design.nullobject; public class Rectangle implements Shape < // sides private final double width; private final double length; public Rectangle() < this(1.0d ,1.0d); >public Rectangle(double width, double length) < this.width = width; this.length = length; >@Override public double area() < // A = w * l return width * length; >@Override public double perimeter() < // P = 2(w + l) return 2 * (width + length); >@Override public void draw() < System.out.println("Drawing Rectangle with area: " + area() + " and perimeter: " + perimeter()); >@Override public boolean isNull() < return false; >>

Below is the code for the Triangle class:

package design.nullobject; public class Triangle implements Shape < // sides private final double a; private final double b; private final double c; public Triangle() < this(1.0d, 1.0d, 1.0d); >public Triangle(double a, double b, double c) < this.a = a; this.b = b; this.c = c; >@Override public double area() < // Using Heron's formula: // Area = SquareRoot(s * (s - a) * (s - b) * (s - c)) // where s = (a + b + c) / 2, or 1/2 of the perimeter of the triangle double s = (a + b + c) / 2; return Math.sqrt(s * (s - a) * (s - b) * (s - c)); >@Override public double perimeter() < // P = a + b + c return a + b + c; >@Override public void draw() < System.out.println("Drawing Triangle with area: " + area() + " and perimeter: " + perimeter()); >@Override public boolean isNull() < return false; >>
  • Now, the most important step is to create a null object class that extends the abstract class or interface and define the do nothing behavior. The do nothing behavior is like a default behavior in case data is not available.
package design.nullobject; public class NullShape implements Shape < // no sides @Override public double area() < return 0.0d; >@Override public double perimeter() < return 0.0d; >@Override public void draw() < System.out.println("Null object can't be draw"); >@Override public boolean isNull() < return true; >>
  • Now, we define the Factory class to create various types of shapes. Please refer to (Strategy vs Factory Design Pattern in Java) to understand the factory pattern. I am creating the ShapeFactory class for this example.
package design.nullobject; public class ShapeFactory < public static Shape createShape(String shapeType) < Shape shape = null; if ("Circle".equalsIgnoreCase(shapeType)) < shape = new Circle(); >else if ("Rectangle".equalsIgnoreCase(shapeType)) < shape = new Rectangle(); >else if ("Triangle".equalsIgnoreCase(shapeType)) < shape = new Triangle(); >else < shape = new NullShape(); >return shape; > >

To keep the example simple, I have not received parameters for the shape sides in the ShapeFactory method. So, the factory is creating the different Shape object with the fixed side values.

package design.nullobject; import design.nullobject.ShapeFactory; public class ShapeMain < public static void main(String[] args) < String[] shapeTypes = new String[] < "Circle", null, "Triangle", "Pentagon", "Rectangle", "Trapezoid">; for (String shapeType : shapeTypes) < Shape shape = ShapeFactory.createShape(shapeType); // no null-check required since shape factory always creates shape objects System.out.println("Shape area: " + shape.area()); System.out.println("Shape Perimeter: " + shape.perimeter()); shape.draw(); System.out.println(); >> >
Shape area: 3.141592653589793 Shape Perimeter: 6.283185307179586 Drawing Circle with area: 3.141592653589793 and perimeter: 6.283185307179586 Shape area: 0.0 Shape Perimeter: 0.0 Null object can't be draw Shape area: 0.4330127018922193 Shape Perimeter: 3.0 Drawing Triangle with area: 0.4330127018922193 and perimeter: 3.0 Shape area: 0.0 Shape Perimeter: 0.0 Null object can't be draw Shape area: 1.0 Shape Perimeter: 4.0 Drawing Rectangle with area: 1.0 and perimeter: 4.0 Shape area: 0.0 Shape Perimeter: 0.0 Null object can't be draw
  • In Java 8, we have the java.util.Optional class to deal with the null references. This class was originally from the Guava API.
Читайте также:  Простейшее выпадающее меню css

Optional

The purpose of the class is to provide a type-level solution for representing optional values instead of using null references. To gain deeper knowledge on using Optional, please refer to Oracle’s article Tired of Null Pointer Exceptions? Consider Using Java SE 8’s.

Below, I am going to demonstrate some of the useful APIs of java.util.Optional . There are several static APIs to creating Optional o bjects:

@Test public void optionalEmptyTest() < Optionalempty = Optional.empty(); assertFalse(empty.isPresent()); >
  • Optional.of() : To create a non-empty Optional object, if we are sure that we have an object that we would like to make it Optional, use the API. If you call this API using null, it will throw the null pointer exception ( NullPointerException ).
@Test public void optionalOfTest() < Shape shape = ShapeFactory.createShape("Circle"); OptionalnonEmpty = Optional.of(shape); assertTrue(nonEmpty.isPresent()); > @Test(expected = NullPointerException.class) public void optionalOfWithNullTest()
  • Optional.ofNullable() : In the code above, both APIs are useful when we are on empty or non-empty. If we are not sure about the object, the object may or may not be null. For this, use the ofNullable API.
@Test public void optionalOfNullableTest() < Shape shape1 = ShapeFactory.createShape("Circle"); OptionalnonEmpty = Optional.ofNullable(shape1); assertTrue(nonEmpty.isPresent()); Shape shape2 = null; Optional empty = Optional.ofNullable(shape2); assertFalse(empty.isPresent()); >

Additional APIs

  • isPresent() : This method returns true if, and only if, the object wrapped in the Optional is not-empty (not null).
@Test public void optionalIsPresentTest() < Shape shape = ShapeFactory.createShape("Circle"); OptionalnonEmpty = Optional.of(shape); assertTrue(nonEmpty.isPresent()); Optional empty = Optional.empty(); assertFalse(empty.isPresent()); >
@Test public void optionalIfPresentTest() < Shape shape = ShapeFactory.createShape("Circle"); OptionalnonEmpty = Optional.of(shape); nonEmpty.ifPresent(circle -> circle.draw()); Optional empty = Optional.empty(); empty.ifPresent(circle -> circle.draw()); >
  • get() : This returns a value if the wrapped object is not null. Otherwise, it throws a no such element exception ( NoSuchElementException ).
@Test public void optionalGetTest() < Shape shape = ShapeFactory.createShape("Circle"); OptionalnonEmpty = Optional.ofNullable(shape); assertNotNull(nonEmpty.get()); > @Test(expected = NoSuchElementException.class) public void optionalGetWithNullTest() < Shape shape = null; Optionalempty = Optional.ofNullable(shape); empty.get(); >
  • orElse() : This is used to retrieve the object wrapped inside the Optional instance. The method has one parameter as a default object. With orElse , the wrapped object is returned if it is present, and the argument given to orElse is returned if the wrapped object is absent.
@Test public void optionalOrElseTest() < Shape shape = ShapeFactory.createShape("Rectangle"); Shape shape1 = ShapeFactory.createShape("Circle"); OptionalnonEmpty = Optional.of(shape1); assertEquals(shape1, nonEmpty.orElse(shape)); Optional empty = Optional.empty(); empty.ifPresent(circle -> circle.draw()); assertEquals(shape, empty.orElse(shape)); >
  • orElseGet() : This method is similar to orElse . The only difference is, instead of taking an object to return if the Optional object is not present, it takes a supplier functional interface, which is invoked and returns the value of the invocation.
@Test public void optionalOrElseGetTest() < Shape shape = ShapeFactory.createShape("Rectangle"); Shape shape1 = ShapeFactory.createShape("Circle"); OptionalnonEmpty = Optional.of(shape1); assertEquals(shape1, nonEmpty.orElseGet(() -> ShapeFactory.createShape("Rectangle"))); Optional empty = Optional.empty(); empty.ifPresent(circle -> circle.draw()); // comparing the area of the shape since orElseGet will create another instance of rectangle assertEquals(shape.area(), empty.orElseGet(() -> ShapeFactory.createShape("Rectangle")).area(), 0.001d); >
  • orElseThrow() : This is similar to orElse . The only difference is it adds a new approach for handling an absent value. Instead of returning a default value when the wrapped object is absent, it throws a given (as parameter) exception.
@Test(expected = IllegalArgumentException.class) public void optionalOrElseThrowWithNullTest() < Shape shape = null; Optionalempty = Optional.ofNullable(shape); empty.orElseThrow(IllegalArgumentException::new); >

Now, we can write the ShapeFactory and Main using Optional , which is demonstrated below:

package design.nullobject; public class ShapeFactoryJava8 < public static OptionalcreateShape(String shapeType) < Shape shape = null; if ("Circle".equalsIgnoreCase(shapeType)) < shape = new Circle(); >else if ("Rectangle".equalsIgnoreCase(shapeType)) < shape = new Rectangle(); >else if ("Triangle".equalsIgnoreCase(shapeType)) < shape = new Triangle(); >else < // no need to have NullShape anymore shape = null; >// using ofNullable because shape may be not null. return Optional.ofNullable(shape); > >

And, the Main class to execute and test the code:

package design.nullobject; import java.util.Arrays; import java.util.Optional; public class ShapeMainJava8 < public static void main(String[] args) < String[] shapeTypes = new String[] < "Circle", null, "Triangle", "Pentagon", "Rectangle", "Trapezoid">; Arrays.asList(shapeTypes).stream().forEach(shapeType -> < OptionaloptionalShape = ShapeFactoryJava8.createShape(shapeType); optionalShape.ifPresent((shape) -> < // null-check is done by ifPresent of Optional System.out.println("Shape area: " + shape.area()); System.out.println("Shape Perimeter: " + shape.perimeter()); shape.draw(); System.out.println(); >); >); > >

Below is the output of the code:

Shape area: 3.141592653589793 Shape Perimeter: 6.283185307179586 Drawing Circle with area: 3.141592653589793 and perimeter: 6.283185307179586 Shape area: 0.4330127018922193 Shape Perimeter: 3.0 Drawing Triangle with area: 0.4330127018922193 and perimeter: 3.0 Shape area: 1.0 Shape Perimeter: 4.0 Drawing Rectangle with area: 1.0 and perimeter: 4.0 

Like this article? Don’t forget to press the like button. Happy coding!

Читайте также:  Php database query class

Need more articles on Design Patterns? Below are some of them I have shared with you.

  • Null Object Pattern in Java
  • Using the Adapter Design Pattern in Java
  • Using the Bridge Design Pattern in Java
  • Strategy vs. Factory Design Patterns in Java
  • Decorator Design Pattern in Java
  • How to Use Singleton Design Pattern in Java
  • Singleton Design Pattern: Making Singleton More Effective in Java

Opinions expressed by DZone contributors are their own.

Источник

Оцените статью