Representing something as blank or absent of something is always a problem in programming. An absence of items, say, in a bag, simply means the bag is empty or the bag does not contain anything. But how do you represent an absence of something in computer memory? For example, an object declared in memory contains some value (it does not matter if the variable is initialized or not) even if it may not make any sense in the context – this is known as garbage values. Programmers can, at best, discard it but the point is that the object declared is not empty. We can initialize it by a value or put a null. However, this still represents some value; even null is something that represents nothing. In this programming tutorial, we analyze the absence of data and null see what Java offers in regards to dealing with this issue.
Before we begin, however, we wanted to point out an article we published recently highlighting some of the Best Online Courses to Learn Java that may be of interest to you.
What is null in Java?
Absence of data in computers is just a conceptual idea; the internal representation is actually contrary to it. A similar idea we can relate it to is set theory, which defines an empty set whose cardinality is 0. But, in actual representation, it uses a symbol called null to mean emptiness. So, if we ask the question, “What does an empty set contain?”, one possible answer would be null, meaning nothing or empty. But, in software development, we know null is also a value.
Typically, the value 0 or all bits at 0 in memory is used to denote a constant, and the name given to it is null. Unlike other variables or constants, null means there is no value associated with the name and it is denoted as a built-in constant with a 0 value in it.
A piece of data is actually represented as a reference pointing to it. Therefore, to represent something in the absence of data, developers must make something up that represents nothing. So null (in Go it is called nil – maybe because they found nil is one less character than null and the lesser the better) is the chosen one. This is what we mean by a null pointer. Thus, we can see that null is both a pointer and a value. In Java, some objects (static and instance variables) are created with null by default, but later they can be changed to point to values.
It is worth mentioning here that null, as a reference in programming, was invented in 1965 by Tony Hoare while designing ALGOL. In his later years he regretted it as a billion dollar mistakestates:
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
This harmless looking thing called null has caused some serious trouble throughout the years. But, perhaps the importance of null cannot totally be discarded in programming. This is the reason many later compiler creators thought it wise to keep the legacy alive. However, Java 8 and later versions tried to provide a type called Optional that directly deals with some of the problems related to the use of null.
Reading: Best Tools for Remote Developers
Problems with the null pointer in Java
The NullPointerException is a common bug frequently encountered by every programmer in Java. This error is raised when we try to dereference an identifier that points to nothing – this simply means that we are expecting to reach some data but the data is missing. The identifier we are trying to reach is pointing to null.
Here is a code example of how we can raise the NullPointerException error in Java:
public class Main { public static void main(String[] args) { Object obj = null; System.out.println(obj.toString()); } }
Running this code in your integrated development environment (IDE) or code editor would produce the following output:
Exception in thread “main” java.lang.NullPointerException: Cannot invoke “Object.toString()” because “obj” is null at Main.main(Main.java:4)
Often in programming, the best way to avoid a problem is to know how to create one. Now, although it is well known that null references must be avoided, the Java API is replete with using null as a valid reference. One such example is as follows. The documentation of the Socket class constructor from the java.net package states the following:
public Socket( InetAddress address, int port, InetAddress localAddr, int localPort ) throws IOException
This Java code:
- Creates a socket and connects it to the specified remote address on the specified remote port. The Socket will also bind() to the local address and port supplied.
- If the specified local address is null, it is the equivalent of specifying the address as the AnyLocal address (see InetAddress.isAnyLocalAddress()).
- A local port number of zero will let the system pick up a free port in the bind operation.
- If there is a security manager, its checkConnect method is called with the host address and port as its arguments. This could result in a SecurityException.
According to Java documentation, the highlighted point clearly means that the null reference is used as a valid parameter. This null is harmless here and used as a sentinel value to mean absence of something (here in case of an absence of a port value in a socket). Therefore, we can see that null is not altogether avoided, although it is dangerous at times. There are many such examples in Java.
How to Handle Absence of Data in Java
A perfect programmer, who always writes perfect code, cannot actually have any problem with null. But, for those of us who are prone to mistakes and need some sort of a safer alternative to represent an absence of something without resorting to innovative uses of null, we need some support. Therefore, Java introduced a type – a class called Optional – that deals with absence values, occurring not due to an error, in a more decent manner.
Now, before getting into any code examples, let’s look at the following excerpt derived from the Java API documentation:
public final class Optional extends Object
This excerpt showcases:
- A container object which may, or may not, contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
- Additional methods that depend on the presence or absence of a contained value are provided, such as orElse() (returns a default value if value not present) and ifPresent() (executes a block of code if the value is present).
- This is a value-based class; Use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided by developers.
In fact, there are a host of optional classes in Java, such as Optional, OptionalDouble, OptionalInt, and OptionalLong – all dealing with a situation where developers are unsure whether a value may be present or not. Before Java 8 introduced these classes, programmers used to use the value null to indicate an absence of value. Because of this, the bug known as NullPointerException was a frequent phenomenon, as we intentionally (or unintentionally) made an attempt to dereference a null reference; a way out was to frequently check for null values to avoid generating exceptions.
These classes provide a better strategy to cope with the situation. Note that all the optional classes are value-based, therefore they are immutable and have various restrictions, such as not using instances for synchronization and avoiding any use of reference equality. In this next section, we will focus on the Optional class specifically. Other optional classes function in a similar manner.
The T in the Optional class represents the type of value stored, which can be any value of type T. It may also be empty. The Optional class, despite defining several methods, does not define any constructor. Developers can determine if a value is present or not, obtain the value if it is present, obtain a default value when the value is not present, or construct an optional value. Check out Java documentation for details on available functions of these classes.
Reading: Best Project Management Tools for Developers
How to use Optional in Java
The code example below shows how we can gracefully deal with objects that return null or an absence of element in Java. The Optional class acts as a wrapper for the object that may not be present:
package org.app; public class Employee { private int id; private String name; private String email; public Employee(int id, String name, String email) { this.id = id; this.name = name; this.email = email; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return “Employee{” + “id=” + id + “, name=”” + name + “” + “, email=”” + email + “” + ‘}’; } } package org.app; import java.util.HashMap; import java.util.Optional; public class Main { private HashMap
Some of the key functions of the Optional class are isPresent() and get(). The isPresent() function determines whether the value is present or not. This function returns a boolean true value if the value is present – otherwise it returns a false value.
A value that is present can be obtained using the get() function. However, if the get() function is called and it does not have a value then a NoSuchElementException is thrown. Ideally, the presence of a value is always checked using the ifPresent() function before calling the get() function.
You can learn more about using the Optional class in Java in our tutorial: How to Use Optional in Java.
Final Thoughts on Null Values in Java
If there is something that programming cannot do away with, yet caution everyone in using, is null. In databases, while storing values, the advice is to avoid storing null values in the tables. A not properly normalized database table can have too many null values. In general, there is not a very clear definition of what an absence of value means in computing. In any event, the problem associated with null values can be handled, to some extent, using the Optional class in Java.
read more Java programming and software development tutorials.