I recently ran into a weird NullPointerException in part of our code:
Exception in thread "main" java.lang.NullPointerException at org.dubh.blog.Graph$Vertex.access$000(Graph.java:17) at org.dubh.blog.Graph.getVerticesConnectedTo(Graph.java:14) at org.dubh.blog.Graph.main(Graph.java:26)
Hmm... access$000? That's odd. The code looked something like this:
01 package org.dubh.blog;
03 import java.util.ArrayList;
04 import java.util.HashMap;
05 import java.util.List;
07 final class Graph
09 private HashMap _vertices = new HashMap();
11 public List getVerticesConnectedTo( Object vertexKey )
13 Vertex vertex = (Vertex) _vertices.get( vertexKey );
14 return vertex.fromEdges;
17 private final class Vertex
19 private final List fromEdges = new ArrayList();
22 public static void main( String args )
24 Graph graph = new Graph();
25 graph.getVerticesConnectedTo( getSomeVertex() );
Can you tell quickly from looking at these two pieces of information what the problem is?
It turns out that getSomeVertex() was returning null, and this was being passed in as the value of vertexKey. Unlike its older cousin, Hashtable, which would throw a NullPointerException if you tried to get null, HashMap.get( null ) returns null, so the vertex variable in getVerticesConnectedTo() was also null.
OK... so why did the NullPointerException happen on line 17 (which is the inner class declaration), instead of line 14, which is where we're actually dereferencing the null variable? Well, it's because the Java compiler creates a super-secret static method for accessing the fields of inner classes. With the geeky power of javap, you can see it being called in the bytecode:
public java.util.List getVerticesConnectedTo(java.lang.Object); Code: 0: aload_0 1: getfield #4; //Field _vertices:Ljava/util/HashMap; 4: aload_1 5: invokevirtual #5; //Method java/util/HashMap.get:(Ljava/lang/Object;)L java/lang/Object; 8: checkcast #6; //class org/dubh/blog/Graph$Vertex 11: astore_2 12: aload_2 13: invokestatic #7; //Method org/dubh/blog/Graph$Vertex.access$000:(Lorg /dubh/blog/Graph$Vertex;)Ljava/util/List; 16: areturn
If the generated method were written in Java it would look something like this:
private final class Vertex
private final List fromEdges = new ArrayList();
private static List access$000( Vertex instance )
Now the reason for the NPE happening before vertex is dereferenced on line 14 is pretty obvious.
Two lessons from this:
1) Follow Josh Bloch's Advice in Effective Java - "Item 23: Check parameters for validity"
A simple null check in the getVerticesConnectedTo method would have produced a much more readable exception:
public List getVerticesConnectedTo( Object vertex )
if ( vertex == null ) throw new NullPointerException( "vertex is null" );
Exception in thread "main" java.lang.NullPointerException: vertex is null at org.dubh.blog.Graph.getVerticesConnectedTo(Graph.java:13) at org.dubh.blog.Graph.main(Graph.java:27)
2) It's almost always better to access fields using method calls. Even in private inner classes.
It would have been better if the Vertex inner class above had provided an accessor method for the fromEdges field. If it had, the exception would have been clearer. A few people worry about the performance of method calls vs. field access. Remember that performance solutions aren't solutions until you can prove as much using a profiler, and that the point is somewhat moot in the above case, since there's effectively a static method call rather than a getfield in the generated bytecode anyway, canceling out the programmer's misguided attempt to save cycles and / or typing. Cough... the programmer in this case, of course, being me :)