Every data type has a default value. For primitives, if they’re numbers, its their form of 0. For booleans, it’s false. For the char type, it’s ASCII 0—which is not literally the character ‘0’, but a NULL value, a sort of way to say “this space contains a thing, and that thing is ‘nothing’”, as distinct from “this is an empty box.”
For objects, then, of any sort, the default value is null. “null” is reserved
in Java, so just as you can’t name a variable “int” or “for” or “while,” you
can’t name it “null” either.
When you create an object, before it gets a value, if you try to access it—say,
to print out its contents—the value you will get on the other end will be null.
If, for example, you’re moving along a List, and you’ve reached
the end of the list, then the “next” pointer won’t point to another element of
the list, but will point to null, and accessing that phantom element (the one
after the last one) will produce a NullPointerException.
This behavior is a core part of how Java manages memory and object references.
The use of null is both practical and intentional—it signals that a
reference exists, but it doesn’t point to any actual object in memory. However,
this design also introduces a common pitfall: attempting to call methods or
access fields on a null reference will trigger a NullPointerException.
For example, if you try to call .length() on a String variable
that’s null, or .next on a null node in a linked list, Java
will throw this exception to alert you that your code is trying to operate on
nothingness. To avoid these errors, it’s considered best practice to
perform explicit null checks before accessing object members.
Java developers often encounter null in more complex scenarios, such
as when working with collections or APIs. For instance, some methods may
return null to indicate the absence of a value—like when searching
for a key that doesn’t exist in a Map, or when a database query finds no
matching row. In these cases, it’s up to the programmer to decide how to
handle null values: should they throw an exception (we’ll cover this
very soon), return a default value, or perhaps propagate the null up
the call stack? This decision can have significant implications for the
robustness and clarity of your codebase.
Look at this example:
public class NullExample {
public static void
main(String[] args) {
String message
= null; // message is declared but not set to a real string
// This would
throw a NullPointerException if uncommented:
//
System.out.println("Message length: " + message.length());
// Safe way:
check for null before using message
if (message !=
null) {
System.out.println("Message length: " + message.length());
} else {
System.out.println("Message is null!");
}
}
}
The String message is declared null, so accessing it a few lines later (that
part is commented out, so it woud not execute) would return an error that, in
this case, would crash the program. That is why it’s so important to take the
safe approach and check whether something is null or not, and only take action
on it if we know it isn’t null, as we do at the end.
No comments:
Post a Comment