Bethany Louise Bethany Louise - 7 months ago 31
Java Question

NullPointerException when adding to ArrayList [long post]

I am working on creating a regex parser for a class project, and I've run into a problem I can't figure out how to fix. Whenever it encounters a parenthesized group, it is supposed to add a placeholder to the

groups
ArrayList where a group can then be captured from a String. The problem is that it throws a NullPointerException whenever it attempts to add to this ArrayList. Here is the
Segment
constructor, where this occurs:

public Segment(String value, boolean capture) throws ParseException {
values = new ArrayList<>();
parse(value);
minimum = 1;
maximum = 1;
matchNot = false;
captureGroup = capture;
if (capture) {
RegexGUI.input.groups.add(""); //error occurs on this line
}
}


Note that
RegexGUI.input
refers to the relevant instance of
Regex
, which the constructor for is here:

public Regex(String value) throws ParseException {
this.value = value;
segments = new ArrayList<>();
groups = new ArrayList<>();
anchorStart = false;
anchorEnd = false;
tokenize(value, true, false);
}


As you can see,
groups
is clearly initialized in the constructor. Also, the
Segment
constructor is only called in the
tokenize()
method in the
Regex
class, and that method is only called by the
Regex
constructor, so there is no possible way I could see that the problem would simply be that
groups
has not been initialized.

The entire stacktrace is here:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at regexparser.Segment.<init>(Segment.java:39)
at regexparser.Regex.tokenize(Regex.java:57)
at regexparser.Regex.<init>(Regex.java:27)
at regexparser.RegexGUI.actionPerformed(RegexGUI.java:80)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6535)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6300)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4891)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4713)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
at java.awt.Container.dispatchEventImpl(Container.java:2280)
at java.awt.Window.dispatchEventImpl(Window.java:2750)
at java.awt.Component.dispatchEvent(Component.java:4713)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)


This is the line of code in
tokenize()
mentioned in the stacktrace:

segments.add(new Segment(value.substring(0, value.indexOf(")")+1), true));


This is the line of code in
actionPerformed()
mentioned in the stacktrace:

input = new Regex(regexInput.getText());


I don't know if this is necessary to post or not, but here are my instance and class variables for each class:

Regex
class:

String value;
ArrayList<Segment> segments;
ArrayList<String> groups;
boolean anchorStart;
boolean anchorEnd;


Segment
class:

ArrayList<String> values;
int minimum;
int maximum;
boolean matchNot;
boolean captureGroup;

final static String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
final static String LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
final static String DIGITS = "0123456789";
final static String[] SETS = {UPPERCASE, LOWERCASE, DIGITS};
final static String WORD = UPPERCASE + LOWERCASE + DIGITS + "_";

final static String WHITESPACE = " \r\n\t\f";


RegexGUI
class:

Container contentPane;
JPanel panel;
GridBagLayout gridbag;
GridBagConstraints c;
JLabel regexPrompt, stringPrompt, result;
JTextField regexInput;
JTextArea stringInput;
JButton test;
static Regex input;
boolean match;


I would appreciate any help you guys can give me. I've tried looking up what might be causing this exception, but the only answer I can find is that
groups
is not initialized. I've searched through my code to try to figure out any way that the
Segment
constructor may be called before
groups
is initialized, but I can't see any way that would be possible.

Answer

Your code is a catch 22

This line:

input = new Regex(regexInput.getText());

Will create the Regex object, then assign it.

However, whilst creating the Regex instance you try to reference the Regex.input instance before its actually finished, so it hasnt yet actually been assigned and is in fact still null.

A reasonably quick fix would be to call the tokenize method after constructing the object. So remove the tokenize call from the constructor and then run something like:

input = new Regex(regexInput.getText());
input.tokenize(...);