Java: Inputting text from a file using split
I am inputting an adjacency list for a graph. There are three columns of data (vertex, destination, edge) separated by a single space. Here is my implementation so far:
FileStream in = new FileStream("input1.txt");
Scanner s = new Scanner(in);
String buffer;
String [] line = null;
while (s.hasNext())
{
buffer = s.nextLine();
line = buffer.split("\\s+");
g.add(line[0]);
System.out.println("Added vertex " + line[0] + ".");
g.addEdge(line[0], line[1], Integer.parseInt(line[2]));
System.out.println("Added edge from " + line[0] + " to " + line[1] + " with a weight of " + Integer.parseInt(line[2]) + ".");
}
System.out.println("Size of graph = " + g.size());
Here is the output:
Added vertex a.
Added edge from a to b with a weight of 9.
Exception in thread "main" java.lang.NullPointerException
at structure5.GraphListDirected.addEdge(GraphListDirected.java:93)
at Driver.main(Driver.java:28)
I was under the impression that
line = buffer.split("\\s+");
would return a 2 dimensional array of Strings to the variable line
. It seemed to work the first time but not the second. Any thoughts?
I would also like some feedback on my implementation of this problem. Is there a better way? Anything to help out a novice! :)
EDIT:
I tried this implementation earlier today and was unsuccessful. I did it again here:
FileStream in = new FileStream("input1.txt");
Scanner s = new Scanner(in).useDelimiter("\\s+");
while (s.hasNext())
{
Scanner line = new Scanner(s.nextLine());
String vertex = line.next();
String destination = line.next();
int weight = line.nextInt();
g.add(vertex);
System.out.println("Added vertex " + vertex + ".");
g.addEdge(vertex, destination, weight);
System.out.println("Added edge from " + vertex + " to " + destination + " with a weight of " + weight + ".");
}
System.out.println("Size of graph = " + g.size());
Output:
Added vertex a.
Exception in thread "main" java.lang.NullPointerException
at structure5.GraphListDirected.addEdge(GraphListDirected.java:93)
at Driver.main(Driver.java:22)
Edit2:
Here is the addEdge function. This is not my own implementation I am using it to save the time of feebly writing my own at this beginning stage...
package structure5;
import java.util.Iterator;
abstract public class GraphList<V,E> extends AbstractStructure<V> implements Graph<V,E>
{
protected Map<V,GraphListVertex<V,E>> dict; // label -> vertex
protected boolean directed; // is gr开发者_开发技巧aph directed?
protected GraphList(boolean dir)
{
dict = new Hashtable<V,GraphListVertex<V,E>>();
directed = dir;
}
public void add(V label)
{
if (dict.containsKey(label)) return; // vertex exists
GraphListVertex<V,E> v = new GraphListVertex<V,E>(label);
dict.put(label,v);
}
abstract public void addEdge(V v1, V v2, E label);
}
Graph.java:
package structure5;
import java.util.Iterator;
public interface Graph<V,E> extends Structure<V>
{
public void add(V label);
public void addEdge(V vtx1, V vtx2, E label);
}
Note: I am leaving out the rest of the methods that don't pertain to the program
Edit3: Here is GraphListDirected.java
public class GraphListDirected<V,E> extends GraphList<V,E>
{
public GraphListDirected()
{
super(true);
}
public void addEdge(V vLabel1, V vLabel2, E label)
{
GraphListVertex<V,E> v1 = dict.get(vLabel1);
GraphListVertex<V,E> v2 = dict.get(vLabel2);
Edge<V,E> e = new Edge<V,E>(v1.label(), v2.label(), label, true); //Line 93
v1.addEdge(e);
}
String.split
returns a String[]
, a one-dimensional array, never a two dimensional array. You can, of course, further split
a String
that was the result of a split
(and so on).
Having said that, since you're already using Scanner
, you should never need to use split
and Integer.parseInt
etc. Just create another Scanner
to scan s.nextLine()
.
Scanner line = new Scanner(s.nextLine());
String from = line.next();
String to = line.next();
int weight = line.nextInt();
I'm not sure what caused the NullPointerException
, although we know from your output that at least one edge was successfully added.
API links
Scanner(String source)
- Constructs a new
Scanner
that produces values scanned from the specified string.
- Constructs a new
On multiple Scanner
The little A-ha!! moment here is the realization that just as you can split
on the result of a previous split
, you can create a Scanner
to scan strings returned from another Scanner
.
String inputText =
"Line1 a b\n" +
"Line2 d e f\n" +
"Line3";
Scanner input = new Scanner(inputText);
while (input.hasNext()) {
Scanner line = new Scanner(input.nextLine());
System.out.println("[" + line.next() + "]");
while (line.hasNext()) {
System.out.println(" " + line.next());
}
}
The above snippet prints:
[Line1]
a
b
[Line2]
d
e
f
[Line3]
This is just a simple example, but you can see the value of this technique when each line is more complex, e.g. when it contains numbers and regex patterns.
On the NullPointerException
You need to add
both the starting and ending vertices, because of the way addEdge
is implemented.
Scanner line = new Scanner(s.nextLine());
String vertex = line.next();
String destination = line.next();
int weight = line.nextInt();
g.add(vertex);
g.add(destination); // <--- ADD THIS LINE!!
g.addEdge(vertex, destination, weight);
This should fix the NullPointerException
.
Hopefully the process of finding this bug has been educational: it took several revisions to the question to gather the relevant information, but finally the culprit of the error has been identified.
As polygenelubricants mentioned, split() returns String[], not String[][].
Note that split() will recompile the regex pattern on every loop iteration. If your input is small, this won't matter, but if your input is large (maybe thousands of iterations), you would be better off using a second Scanner inside the loop, or using a Pattern that's compiled outside the loop.
To get to the bottom of the NullPointerException, I'd suggest using a debugger (like the one included in Eclipse) and setting a breakpoint at line 93 of GraphListDirected.java (the line reported in the stacktrace). Each time the breakpiont pauses your program at that line, double-check all your values to make sure they are what you would expect to see.
精彩评论