Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Throwing NPEs (Part 1): Redeclaration

DZone's Guide to

Throwing NPEs (Part 1): Redeclaration

This first post in a series on dreaded null pointer exceptions considers a common cause: redeclaring fields as variables. See how this comes up in testing.

· Java Zone
Free Resource

Managing a MongoDB deployment? Take a load off and live migrate to MongoDB Atlas, the official automated service, with little to no downtime.

Here's a question I see a lot: "Why does my code throw a null pointer exception?"

Common reason #1: Redeclaration

  • Using @BeforeClass or @Before can set up data for use in tests
  • Any ‘variables’ we instantiate need to be ‘fields’ rather than variables
  • We want to instantiate them in the setup method rather than redeclare them

Example of the Problem

I know I will use an Adder in my test, so I create it as a field:

public class WhyCodeThrowsNullPointerExceptionTest {

    Adder adder;


I don’t want to re-instantiate it each time so I make a @BeforeClass method to instantiate it:

@BeforeClass
public static void setupAdder(){
    Adder adder = new Adder();
}


I just made a semantic coding error. This won’t be caught by a compiler, but it will cause my @Test to fail with a null pointer exception.

@Test
public void canAddTwoPlusTwo(){

    Assert.assertEquals(4,adder.add(2,2));
}


The above test will fail with a null pointer exception:

java.lang.NullPointerException
    at com.javafortesters.faq.nullpointerexception.
WhyCodeThrowsNullPointerExceptionTest.canAddTwoPlusTwo
(WhyCodeThrowsNullPointerExceptionTest.java:29)
...


What Went Wrong?

In the setup method, I really wanted to assign a value to the field. Instead, I created a new variable with the same name:

Adder adder = new Adder();


I really wanted:

adder = new Adder();


And to support that, the field really needs to be declared as

static:

static Adder adder;


How to Avoid It

IDE Syntax Highlighting

If I was editing this in an IDE, then I would see that the adder in the following line is never used:

Adder adder = new Adder();


It will be colored grey or some other IDE indication.

static Methods Need static Fields

In order for the field to be used in the static method, it needed to be static.

If I had used it in the setup method:

Adder adder;

@BeforeClass
public static void setupAdder(){
    adder = new Adder();
}


Then I would have seen a syntax error in the code because:

Non-static field 'adder' cannot be referenced from a static context

Refactor to Fields

Had I written the @Test code first, then I would have started with:

@Test
public void canAddTwoPlusTwo(){
    Adder adder = new Adder();
    Assert.assertEquals(4,adder.add(2,2));
}


Then, when I created a second @Test, I would have seen duplication, and I might have chosen to remove that duplication by creating adder as a field, and I could have done that with an automated refactoring of Extract to a field where it's initialized as a ‘field declaration’:

Which might have generated the following code:

private final Adder adder = new Adder();


This removes the need for an @BeforeClass or @Before construct entirely

I could have refactored it to be initialized in the constructor:

private final Adder adder;

public WhyCodeThrowsNullPointerExceptionTest() {
    adder = new Adder();
}


This removes the need for an @BeforeClass or @Before construct entirely

I might have looked at the above code and decided that I needed a @BeforeClass or @Before construct to make the code readable, in which case I could have added the method, but I don’t think I would have declared a new variable because I have a working code example that I’m moving.

In General

  • Try to write one test at a time so that if you have a problem, it is easier to identify where the problem is.
  • Try to write working isolated tests and then refactor to a more general solution when you need it. That way, you know it was working, so you just have to work backwards to find out what went wrong.
  • Try to use automated IDE refactoring rather than moving code around manually.
  • Use the IDE syntax highlighting to help spot any issues.

If you want to experiment with code that recreates this problem, then have a look at
WhyCodeThrowsNullPointerExceptionTest.java in javaScratchpad.

MongoDB Atlas is the easiest way to run the fastest-growing database for modern applications — no installation, setup, or configuration required. Easily live migrate an existing workload or start with 512MB of storage for free.

Topics:
java ,null pointer exception ,redeclaration ,variables ,fields ,tutorial

Published at DZone with permission of Alan Richardson, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}