30

I know I can find out if a variable is null in Java using these techniques:

  • if (var==null) -> too much work
  • try { ... } catch (NullPointerException e) { ...} -> it tells me what line is throwing the exception
  • using the debugger -> by hand, too slow

Consider this line of code:

if (this.superSL.items.get(name).getSource().compareTo(VIsualShoppingList.Source_EXTRA)==0)  {

I would like to know if there's a generic way to find out programatically what variable (not just the line) is throwing the NullPointerException in a certain area of code. In the example, knowing that

5
  • 6
    Hm, it would be easier to find the NullPointerException if this wasn 't a one-liner. It is really hard to follow such code. Commented Apr 19, 2010 at 13:59
  • 11
    Considering your options, I'd just point that "too much work" might actually mean a lot less work in the long run. Commented Apr 19, 2010 at 13:59
  • 3
    Turn this into a proper block. You'll find the problem in no time. Commented Apr 19, 2010 at 14:03
  • 1
    Don't forget that using an exception as a control-flow mechanism is a really bad thing... Commented Apr 19, 2010 at 14:13
  • 1
    10 years later, JEP 358 will help: see my answer below Commented Nov 18, 2019 at 5:28

8 Answers 8

31

Since it's possible to cause a null pointer exception without even involving a variable:

throw new NullPointerException();

I would have to say that there is no generic way to pin down a null pointer exception to a specific variable.

Your best bet would be to put as few as possible statements on each line so that it becomes obvious what caused the null pointer exception. Consider refactoring your code in the question to look something like this:

List items = this.superSL.items;
String name = items.get(name);
String source = name.getSource();
if (source.compareTo(VIsualShoppingList.Source_EXTRA) == 0)  {
    // ...
}

It's more lines of code to be sure. But it's also more readable and more maintainable.

Sign up to request clarification or add additional context in comments.

1 Comment

are there languages that can tell you which variable is responsible? (or IDEs) ?
15

You might consider, as announced here, the JDK 14 which should include the JEP 358:

JEP 358: Helpful NullPointerExceptions

Suppose an NPE occurs in this code:

a.b.c.i = 99;

The filename and line number do not pinpoint exactly which variable was null.
Was it a or b or c?

A similar problem occurs with array access and assignment. Suppose an NPE occurs in this code:

a[i][j][k] = 99;

The filename and line number do not pinpoint exactly which array component was null.
Was it a or a[i] or a[i][j]?

Description:

If the more complex statement a.b.c.i = 99; throws an NPE, the message would dissect the statement and pinpoint the cause by showing the full access path which led up to the null:

Exception in thread "main" java.lang.NullPointerException: 
        Cannot read field "c" because "a.b" is null
    at Prog.main(Prog.java:5)

Again: to be tested with JDK 14.


Holger adds in the comments:

For the expression a[i][j][k], there’s also the possibility that either, i, j, or k has type Integer and is null, so unboxing fails.

In real life scenarios, the expression to the right of the = might bear potential for NPE too.

I tried with jdk-14.0.1

it works; it produces a message like

Cannot invoke "java.lang.Integer.intValue()" because "i" is null then.

When the method has been compiled without debug information, it will use something like "<local8>" instead of "i", but that’s unavoidable.

6 Comments

For the expression a[i][j][k], there’s also the possibility that either, i, j, or k has type Integer and is null, so unboxing fails. In real life scenarios, the expression to the right of the = might bear potential for NPE too.
@Holger Will that (i being null) be detected by JEP 358 in this case?
I didn’t try, but since this is easy to spot in the execution (the cause being an invocation of intValue() on a null reference) and determining the sub-expression is not different to identifying, e.g. a[i] being null, I’d expect this. I think, I will make a try later this day.
Just verified that it works; it produces a message like Cannot invoke "java.lang.Integer.intValue()" because "i" is null then. When the method has been compiled without debug information, it will use something like "<local8>" instead of "i", but that’s unavoidable.
@Holger That seems more precise/accurate than in previous JDK versions.
|
6

Sorry, no, there is not a simple programmatic way to determine which variable or method call is the source of the exception. You could use something like Aspect-Oriented Programming (AOP), e.g. AspectJ, but this is not inherent to the language and is not generally incorporated into a program simply for debugging purposes.

  • if (var==null) -> too much work
  • try { } catch() { }
  • Debugger

I know you don't want to hear this, but these are simply the cost of doing business.

if (this.superSL.items.get(name).getSource().compareTo(VIsualShoppingList.Source_EXTRA)==0)  {

It is unusual to see so many strung together method calls. I believe you best bet is to get in the habit of breaking these up more - not necessary down to 1 call per line, but fewer than this. Why?

1) Correctness - is it valid in the design for one of these calls to return null? If so, you should break it out, test it, and handle it appropriately.

2) Understandability - it would be easier for future maintainers (including future you) to understand if you intermediate, well-named variables to help clarify what is happening on this line.

3) Efficiency - usually when you go so deep into a graph (stringing together a series of method calls), its likely you will need to go back down around there later. Capturing this intermediate value in an intermediate variable means avoiding making one or more method calls again.

4) Debugging - as indicating by your question, spltiting a complex line like this up simplifies debugging. by narrowing down the possible source of the exception.

Comments

2

What do you mean by "using the debugger -> by hand, too slow"? If your code is properly structured, then there won't be more than two or three variables used on the same line. Is it so slow to check them? You don't have NullPointers every minute.

1 Comment

> What do you mean by "using the debugger -> by hand, too slow"? - For example, from my experience, when you have to debug remotely. But sometimes remote debugger attachment is not even possible.
1

I know you suggested that (var==null) is too much work, but, as Miguel stated in the comments, that is what I would go with.

Comments

1

I think you should notice Demeters Law.

There aren't many people following it strictly, because it results in a lot of delegate methods.
But getting too far from it will result in dependencies on inner structures that should be transparent.

1 Comment

Just because stuff is strung together, doesn't mean your violating Demeter's Law. It's mainly when you're grabbing a reference through chaining, then modifying something. There is nothing wrong with reaching down to display or compare a value in a read-only fashion.
0

Unfortunately, Java will not show you the name of the variable or the exact position of an error other than the line number. If you use Eclipse you can use nullable annotations however, see http://www.fosslc.org/drupal/content/bye-bye-npe for example. See Which @NotNull Java annotation should I use? for other annotation systems.

Comments

0

What has worked really beautifully to me is catching the exception where it normally gets thrown and then using Log to see whether any of them have 'null' values.

My code:

 try {
                 if (description_visible) advice_title_cur.setText(all_title_array[pos]);
                 else advice_title_cur.setText(all_title_array[pos] + "...");

             } catch (NullPointerException e) {
                 e.printStackTrace();
                 Log.e("My name", "description_visible " + description_visible);
                 Log.e("My name", "advice_title_cur " + advice_title_cur);
                 Log.e("My name", "all_title_array " + all_title_array);
                 Log.e("My name", "pos " + pos);
             }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.