Resources
5 min read
Last updated:
Null is a reserved word (keyword) in Java for literal values. It is a literal similar to the true and false. In Java, null is a keyword much like the other keywords public, static or final. It is just a value that shows that the object is referring to nothing. The invention of the word “null” originated to denote the absence of something. For example, the absence of the user, a resource, or anything. But, over the years it puts Java programmers in trouble due to the disturbing null pointer exception. When you declare a boolean variable, it gets its default value as false.
The reserved word null is case sensitive and cannot be written as Null or NULL as the compiler will not recognize them and will certainly give an error.
Generally speaking, null are used as a special value to signify:
- Uninitialized state
- Termination condition
- Non-existing object
- An unknown value
Contents
Types of variables in Java
There are two types of variables in Java. These are reference types and primitive types. Primitive types are the ones that would hold values and reference types are the ones that can store references. Examples of primitive variables include int, Boolean, char, short, float, long and double. The reference variables will store null if they are explicitly referencing an object in memory. The main difference between primitive and reference type is that primitive type always has a value, it can never be null but reference type can be null, which denotes the absence of value.
Read our How to Integrate Java guide to learn more about Java and its architecture, components, and concepts. It provides a detailed overview of Java, before outlining how to integrate Java with Logit.io for enhanced monitoring and analysis.
It is a very important concept in Java. The original intention of inventing null was to denote the absence of something. null has a number of properties as we see below;
Properties of null
null as a default
Every primitive type of variable has a default value (e.g int has 0, boolean has false) if not initialised at the same time of declaration. Similarly null is the default value of any reference type of variable which is not initialised at the time of declaration. This is true for all kinds of variables, instance variable or static variable, except that the compiler will warn you if you use a local variable without initialising them.
null is used for casting to other types
null is neither an object nor a type. It’s just a special value, which can be assigned to any reference type. Typecasting null to any reference type is fine at both compile-time and runtime and it will not throw any error or exception,
It is imperative to note that null can only be assigned to reference types. We cannot assign null to primitive variables e.g int, double, float, or boolean. If we try to do so, then the compiler will complain.
null as an instanceOf operator
The java instanceof operator which is also known as type comparison operator, tests whether the object is an instance of the specified type (class or subclass or interface). It also compares the instance with type and returns either true or false. If the instanceof operator is applied with any variable that has a null value, it returns false.
NullPointer Exception (NPE)
NullPointerException is a runtime exception. In Java, a special null value can be assigned to an object reference. NullPointerException is thrown when an application attempts to use an object with a null value.
Autoboxing and unboxing
During auto-boxing and unboxing operations, the compiler simply throws a Nullpointer exception error if a null value is assigned to a primitive boxed data type.
Static vs Non static Methods
We cannot call a non-static method on a reference variable with null value, it will throw NullPointerException, but we can call a static method with reference variables with null values. Since static methods are bonded using static binding, they won’t throw Null pointer Exception.
Null Operations
Operations involving null are extremely fast and easy to perform at run-time. There are only two kinds of operations;
Initialise or set a reference to null (e.g name = null): The only thing to do is to change the content of one memory cell (e.g. setting it 0).
Check if a reference points to null (e.g. if name == null): The only thing to do is to check if the memory cell of the reference holds the value 0.
Tips to Handle Null
After elaborating what null is and what it's all about, it would be great to close the discussion with some tips on how you as a developer can handle this issue. Below are some tips you can start using today.
Use exceptions Over Nulls
One strange case when you might see people using null is exceptional situations. This is an inherently error prone practice, as critical errors can be omitted or resurface in different places of the system, causing debugging to be a pain. Therefore, always throw an exception instead of returning null if something went wrong.
Test your code
Well this advice is related to all kinds of bugs, not just unexpected nulls. Testing your code thoroughly using an environment similar to production is a great way to prevent NPEs. Never release a piece of code without making sure it works. There’s no such thing as “a quick, simple fix that doesn’t require testing.”
Validate Public API Arguments
It is possible to use the principle of not passing nulls with reasonable success, but when you’re exposing a public API, you have no control over its users and what they pass to your functions. For this reason, always check the arguments being passed to your public APIs for correctness. If your only concern is the nullity of the argument, consider using the requireNonNull function from the Objects class;
Use Objects Methods as Stream Predicts
Although Objects.isNull and Objects.nonNull are not the best fit for typical null checks, they are a perfect fit to use with streams. The filtering or matching lines with them read (arguably) much better than those with operators. This is the very reason they were introduced in the JDK.
Optional is not for Fields
Optional was designed to indicate missing return values. One tempting case that it was not designed for and surely is not necessary for is class fields. By means of encapsulation, you should have full control over the field's value, including null. On the other hand, making fields explicitly Optional might bring you weird problems like:
How should you write a constructor or setter for such a field?
You have to deal with the Optional even in cases when you’re sure that the value is there.
How should automapper handle those fields?
Therefore, use direct references for fields and carefully analyse whether a field can be null or not at any given point. If your class is well-encapsulated, this should be fairly easy.
How is null represented in Java Bytecode?
Java bytecode, which is the instruction set for the Java Virtual Machine (JVM), has specific operations to handle 'null' values efficiently. To represent 'null' in Java bytecode, three distinct instructions are primarily utilized.
aconst_null: This instruction is used to push a 'null' onto the stack. For example, when you initialize an object with null, like , is the instruction executed.
ifnull: This checks if the object is null. It is usually used in conditionals to determine whether a reference is null or not. For instance, in the statement , the instruction will execute.
ifnonnull: This is the counterpart to and checks if the object is not null. It functions similarly in conditions but in the opposite way, ensuring the reference holds a non-null value.
These operations ensure that dealing with null values is straightforward and efficient within the Java ecosystem, aiding in clear and effective bytecode execution. This tailored handling helps prevent null-related errors and optimizes performance where null checks are necessary.
Final thoughts
Null, though can be a bit problematic for both amateur and professional developers, knowing its properties and how to handle it will be a great way to make it less of a barrier to you. Using exceptions over nulls, testing code, validating public API arguments are just some of the tips you can use in dealing with null.
With Logit.io, you can follow our simple Java integration to send Java traces to Logit.io. After conducting this, you can then begin using the best in class open source tools as hosted solutions, such as hosted Jaeger. Simply, launch hosted Jaeger directly from the dashboard to conduct Java tracing and Java monitoring.
Our observability platform offers unparalleled flexibility and affordability. It comes with no vendor lock-in, transparent pricing, no charges for data egress, and no mandatory multi-year commitments. If you’re interested in finding out more about our platform, don’t hesitate to get in contact or get started with a 14-day free trial.
Unlock complete visibility with hosted ELK, Grafana, and Prometheus-backed Observability
Start Free TrialIf you found this post informative then why not check out our previous guide on the best open-source logging tools?