What is a Null Pointer Exception and how to fix it?
What is a Null Pointer Exception (java.lang.NullPointerException
) and why can it occur?
What methods and tools should I use to determine the cause of this exception that causes the application to terminate prematurely?
Translation of the question " What is a Null Pointer Exception, and how do I fix it?" @Ziggy.
4 answers
When you declare a variable of a reference type, you are actually creating a reference to an object of that type. Consider the following code for declaring an int variable:
int x;
x = 10;
In this example, the variable x
is of type int
and Java initializes it as 0. When you assign the variable a value of 10 (the second line), this value is stored in the memory location referenced by x
.
But when you declare a reference type, the process looks different. Let's look at the following code:
Integer num;
num = new Integer(10);
In the first line, the variable num
is declared, its type does not belong to the built-in, therefore, the value is a reference (the type of this variable, Integer
, is a reference type). Since you haven't yet specified what you're going to refer to, Java will assign the variable the value Null
, meaning "I'm not referring to anything".
In the second line, the keyword new
is used to create an object of type Integer
. This object has an address in memory that assigned to the num
variable. Now, with the num
variable, you can access the object using the dereference operator .
.
The exception you mention in the question occurs if you declared a variable but did not create an object, that is, if you try to dereference num
before created the object, you get NullPointerException
. In the simplest case, the compiler will detect the problem and report that
num
may not have been initialized
Which says, " perhaps the variable num
is not initialized."
Sometimes the exception is caused precisely because the object was not actually created. For example, you might have the following function:
public void doSomething(Integer num){
// Работаем с num
}
In this case, the creation of the object (variable num
) lies with the calling code, meaning you assume that it was created earlier-before calling the doSomething
method. Unfortunately, the next method call is quite possible:
doSomething(null);
In this case, value of the variable num
will be null
. The best way to avoid this exception is to check for equality to zero. As a result, the function doSomething
should be rewritten as follows:
public void doSomething(Integer num){
if (num != null) {
// Работаем с num
}
}
As an alternative to the previous example, you can tell the calling code that the method was called with incorrect parameters, for example, using IllegalArgumentException
.
public void doSomething(Integer num){
if (num == null)
throw new IllegalArgumentException("Num не должен быть null");
// Работаем с num
}
Also, pay attention to the question " What is stack trace and how to use it to find errors when application development?".
Translation of the answer " What is a Null Pointer Exception, and how do I fix it?" @Vincent Ramdhanie.
In java8, the Optional
class was added to prevent NullPointerException
, although it is not always possible to use it correctly. Here is a link with recommendations on how to use Optional
A typical solution with a check on null
Article article = getFirstJavaArticle();
if (article == null) {
article = fetchLatestArticle();
}
And now the solution using Optional<T>
. Imagine that getFirstJavaArticle()
returns Optional<Article>
getFirstJavaArticle()
.orElseGet(this::fetchLatestArticle);
The solution with Optional
allows us to avoid code with checks on null
and work in a functional style. It is worth noting that Optional is not a panacea for all ills
The NullObject {[26 pattern is also used to prevent
NullPointerException
]}
Abstract Entity class
public abstract class AbstractCustomer {
protected String name;
public abstract String getName();
}
Real implementation
public class RealCustomer extends AbstractCustomer {
public RealCustomer(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
Implementation NullObject
public class NullCustomer extends AbstractCustomer {
@Override
public String getName() {
return "Not Available in Customer Database";
}
}
Usage (as an example)
public class CustomerFactory {
public static final String[] names = {"Rob", "Joe", "Julie"};
public static AbstractCustomer getCustomer(String name){
for (int i = 0; i < names.length; i++) {
if (names[i].equalsIgnoreCase(name)){
return new RealCustomer(name);
}
}
return new NullCustomer();
}
}
Instead of returning null
, we return an instance of the class NullCustomer
and do not fall from NullPointerException
. But as it seems to me there is a small Overhead: you need to create an inheritance hierarchy.
This is an Exception that occurs when you refer to an object that is = null(not initialized) or trying to call methods/access variables of an object that is = null. The solution to this problem:
Checking for null,
if(Твой объект==null){//Your code}
try{}catch(NullPointerException e){//Your code}
When a null is thrown to you, it usually specifies a "row hierarchy"(which, as called, is what led you to null). And there you can see where your object is not initialized, there and you can immediately fix the error.
It can occur in arrays/lists when you call an object with the number n, despite the fact that the object is not previously written there. Like, everything))
I recommend using Optional
to prevent NPE. This class was introduced in java 8.
For example,
@Entity
public class Car {
@Id
@GeneratedValue
private Long id;
@Column(name = "name")
@NotNull
private String name;
}
Repository:
public interface CarRepository extends JpaRepository<Car, Long> {
Optional<Car> findById(Long id);
}
Service:
@Service
public class CarService {
private CarRepository carRepository;
@Autowired
public CarService(CarRepository carRepository) {
this.carRepository = carRepository;
}
public Car findById(Long id) {
Car car = carRepository.findById(id).orElseThrow(() ->
new RuntimeException("Requested entity was not found"));
car.getHolder().setPassword(null);
return car;
}
}
The controller:
@RestController
@RequestMapping("/api")
public class CarController {
private CarService carService;
@Autowired
public CarController(CarService carService) {
this.carService = carService;
}
@RequestMapping(value = "/cars/{id}", method = RequestMethod.GET)
public ResponseEntity<Car> getCar(@PathVariable Long id) {
try {
Car carToFind = carService.findById(id);
return ResponseEntity.status(HttpStatus.OK).body(carToFind);
} catch (Exception ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}
}
}
In this case, if the repository can't find the machine, it won't throw out the NPE.
Optional
helps to avoid checks on null
and to shorten the code and improve its readability.