If you are a
java developer, many times you may fed up with handling NullPointer exceptions.
Usually NullPointerException stops your program executing further, unless you
handle them properly. Java8 solved NullPointerException problem by providing
java.util.Optional<T> class. Optional class encapsulates an optional
value, used to represent null with
absent
value.
What is NullPointerException?
NullPointerException
is a runtime exception, thrown when an application attempts to use an object
reference, having the null value.
Lets take a
simple example, how we are dealing with NullPointerExceptions prior to Java8.
Lets say I
had three classes Employee, Address, Passport.
class Employee{ private String firstName; private String lastName; private int age; private Passport passport; private Address tempAddress; private Address permAddress; } class Address { private String street; private String city; private String state; private String country; private String pin; } class Passport { private String PassportNum; private Date validFrom; private Date validTo; }
Employee
must has firstName, id and age
Employee may
has lastName (Not necessary)
Employee may
have permanent address (Not necessary)
Employee may
have temporary address (Not necessary)
Employee may
have passport (Not necessary).
So while
printing details information about an employee, we need to check null condition
for all optional properties like lastName, tempAddress, permAddress, passport
like following.
public String getEmployeeDetails(Employee employee) { if (employee == null) { return "unknown"; } StringBuilder builder = new StringBuilder(); String lastName = employee.getLastName(); if (lastName == null) { lastName = "unknown"; } Passport passport = employee.getPassport(); if (passport == null) { passport = new Passport("", null, null); } Address permAddress = employee.getPermAddress(); if (permAddress == null) { permAddress = new Address(); } Address tempAddress = employee.getTempAddress(); if (tempAddress == null) { tempAddress = new Address(); } return builder.append(employee.getFirstName()).append(lastName).append(employee.getId()).append(employee.getAge()).append(passport).append(permAddress).append(tempAddress).toString(); }
Problems with above approach
1.
Don’t
you think checking for null conditions for most of the attributes increase code
complexity?
2.
If
you miss to check null condition for any property like tempAddress, again you
end up in NullPointerException.
Using
Optional class can solve this problem. Following is the complete application
for above example. Next I am going to explain Optional class in detail and
rewrite the same example using Optional class.
import java.util.Date; public class Passport { private String PassportNum; private Date validFrom; private Date validTo; Passport() { this("unknown", null, null); } public Passport(String passportNum, Date validFrom, Date validTo) { super(); PassportNum = passportNum; this.validFrom = validFrom; this.validTo = validTo; } public String getPassportNum() { return PassportNum; } public void setPassportNum(String passportNum) { PassportNum = passportNum; } public Date getValidFrom() { return validFrom; } public void setValidFrom(Date validFrom) { this.validFrom = validFrom; } public Date getValidTo() { return validTo; } public void setValidTo(Date validTo) { this.validTo = validTo; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Passport [PassportNum=").append(PassportNum) .append(", validFrom=").append(validFrom).append(", validTo=") .append(validTo).append("]"); return builder.toString(); } }
public class Address { private String street; private String city; private String state; private String country; private String pin; private static final String DEFAULT = "unknown"; public Address() { this(DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT); } public Address(String street, String city, String state, String country, String pin) { super(); this.street = street; this.city = city; this.state = state; this.country = country; this.pin = pin; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getState() { return state; } public void setState(String state) { this.state = state; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getPin() { return pin; } public void setPin(String pin) { this.pin = pin; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Address [street=").append(street).append(", city=") .append(city).append(", state=").append(state) .append(", country=").append(country).append(", pin=") .append(pin).append("]"); return builder.toString(); } }
public class Employee { private String firstName; private String lastName; private int age; private Passport passport; private Address tempAddress; private Address permAddress; private int id; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Passport getPassport() { return passport; } public void setPassport(Passport passport) { this.passport = passport; } public Address getTempAddress() { return tempAddress; } public void setTempAddress(Address tempAddress) { this.tempAddress = tempAddress; } public Address getPermAddress() { return permAddress; } public void setPermAddress(Address permAddress) { this.permAddress = permAddress; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Employee [firstName=").append(firstName) .append(", lastName=").append(lastName).append(", age=") .append(age).append(", passport=").append(passport) .append(", tempAddress=").append(tempAddress) .append(", permAddress=").append(permAddress).append("]"); return builder.toString(); } }
public class EmployeeUtil { public static String getEmployeeDetails(Employee employee) { if (employee == null) { return "unknown"; } StringBuilder builder = new StringBuilder(); String lastName = employee.getLastName(); if (lastName == null) { lastName = "unknown"; } Passport passport = employee.getPassport(); if (passport == null) { passport = new Passport("", null, null); } Address permAddress = employee.getPermAddress(); if (permAddress == null) { permAddress = new Address(); } Address tempAddress = employee.getTempAddress(); if (tempAddress == null) { tempAddress = new Address(); } return builder.append(employee.getFirstName()).append(lastName).append(employee.getId()) .append(employee.getAge()).append(passport).append(permAddress) .append(tempAddress).toString(); } public static void main(String args[]){ Employee employee = new Employee(); employee.setFirstName("Hari Krishna"); employee.setAge(26); String empDetails = getEmployeeDetails(employee); System.out.println(empDetails); } }
Optional class
Optional class provides number of
methods like ifPresent, orElse, orElseGet to work with null values.
How to create an Optional object?
Following statement creates an Address
object.
Optional<Address> addr =
Optional.of(new Address());
How to create empty object?
Following statement creates empty
Optional object.
Optional<Address> sc =
Optional.empty();
Following are all the methods of
Optional class in brief
Method
|
Description
|
public static <T>
Optional<T> empty()
|
Returns an empty optional object.
|
public static <T>
Optional<T> of(T value)
|
Returns an Optional with the
specified present non-null value. Throws NullpointerException, if value is
null
|
public static <T>
Optional<T> ofNullable(T value)
|
Returns an Optional describing the
specified value, if non-null, otherwise returns an empty Optional.
|
public T get()
|
If a value is present in this
Optional, returns the value, otherwise throws NoSuchElementException.
|
public boolean isPresent()
|
Return true if there is a value
present, otherwise false.
|
public void ifPresent(Consumer<?
super T> consumer)
|
If a value is present, invoke the
specified consumer with the value, otherwise do nothing.
|
public Optional<T>
filter(Predicate<? super T> predicate)
|
If a value is present, and the value
matches the given predicate, return an Optional describing the value,
otherwise return an empty Optional.
|
public <U> Optional<U>
map(Function<? super T,? extends U> mapper)
|
If a value is present, apply the
provided mapping function to it, and if the result is non-null, return an
Optional describing the result. Otherwise return an empty Optional.
|
public T orElse(T other)
|
Return the value if present,
otherwise return other.
|
public T orElseGet(Supplier<?
extends T> other)
|
Return the value if present,
otherwise invoke other and return the result of that invocation.
|
public <X extends Throwable> T
orElseThrow(Supplier<? extends X> exceptionSupplier)throws X extends
Throwable
|
Return the contained value, if
present, otherwise throw an exception to be created by the provided supplier.
|
‘getEmployeeDetails’
method as explained above can be rewritten using Optional class like following.
public static String getEmployeeDetailsUsingOptional(Employee employee) { StringBuilder builder = new StringBuilder(); return builder.append(employee.getFirstName()) .append(employee.getLastName().orElse("unknown")) .append(employee.getId()).append(employee.getAge()) .append(employee.getPassport().orElse(new Passport())) .append(employee.getPermAddress().orElse(new Address())) .append(employee.getTempAddress().orElse(new Address())) .toString(); }
Find
complete working application below.
import java.util.Optional; public class Employee { private String firstName; private Optional<String> lastName = Optional.empty(); private int age; private Optional<Passport> passport = Optional.empty(); private Optional<Address> tempAddress = Optional.empty(); private Optional<Address> permAddress = Optional.empty(); private int id; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public Optional<String> getLastName() { return lastName; } public void setLastName(Optional<String> lastName) { this.lastName = lastName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Optional<Passport> getPassport() { return passport; } public void setPassport(Optional<Passport> passport) { this.passport = passport; } public Optional<Address> getTempAddress() { return tempAddress; } public void setTempAddress(Optional<Address> tempAddress) { this.tempAddress = tempAddress; } public Optional<Address> getPermAddress() { return permAddress; } public void setPermAddress(Optional<Address> permAddress) { this.permAddress = permAddress; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Employee [firstName=").append(firstName) .append(", lastName=").append(lastName).append(", age=") .append(age).append(", passport=").append(passport) .append(", tempAddress=").append(tempAddress) .append(", permAddress=").append(permAddress).append(", id=") .append(id).append("]"); return builder.toString(); } }
import java.util.Date; import java.util.Optional; public class EmployeeUtil { public static String getEmployeeDetailsUsingOptional(Employee employee) { StringBuilder builder = new StringBuilder(); return builder.append(employee.getFirstName()) .append(employee.getLastName().orElse("unknown")) .append(employee.getId()).append(employee.getAge()) .append(employee.getPassport().orElse(new Passport())) .append(employee.getPermAddress().orElse(new Address())) .append(employee.getTempAddress().orElse(new Address())) .toString(); } public static void main(String args[]) { Employee employee = new Employee(); employee.setFirstName("Hari Krishna"); employee.setAge(26); employee.setPassport(Optional.of(new Passport("abcdf12345", new Date(), new Date()))); String empDetails = getEmployeeDetailsUsingOptional(employee); System.out.println(empDetails); } }
Output
Hari Krishnaunknown026Passport [PassportNum=abcdf12345, validFrom=Wed Jul 22 12:41:40 IST 2015, validTo=Wed Jul 22 12:41:40 IST 2015]Address [street=unknown, city=unknown, state=unknown, country=unknown, pin=unknown]Address [street=unknown, city=unknown, state=unknown, country=unknown, pin=unknown]
No comments:
Post a Comment