Null pointer exception in iterating and unable to search a node. The delete and replace methods are the ones that have problems
import javax.swing.*;
import java.io.*;
class MyDatabase implements Database {
Node head = null, tail = null, rover = null;
String ako;
File myFile = new File("sample.dat");
Node n = new Node();
Node current; Node p;
Node x = new Node();
public void insert(Node myNewNode) {
if (head == null){
head = myNewNode;
head.next = null;
}
else {
tail = head;
while(tail.next != null)
tail = tail.next;
tail.next = myNewNode;
myNewNode.next = null;
}
current = head;
}
public boolean delete(Node nodeToDelete) {
//the delete and replace methods are the ones that have problems
current = head;
p = head;
head = null;
//here, no matter what you enter, this if statement is never executed. Yes, never. even if they are equal.
if(nodeToDelete.title == head.title) {
head = head.next;
return true;
}
else{
开发者_如何学JAVAwhile(current != nodeToDelete)
current = current.next;//Null Pointer exception here
while(p.next != nodeToDelete)
p = p.next;//Null Pointer exception here
current = current.next;
p = current;
}
current = head;//this is for listIterator purposes.
return true;
}
public boolean replace(Node nodeToReplace, Node myNewNode) {
//the delete and replace methods are the ones that have problems
//here i tested if the head.title and nodeToReplace.title have values
//the println correctly prints the value that I input
current = head;
String s = head.title;// for example i entered "max"
String s1 = nodeToReplace.title;// i also entered "max"
System.out.println(s);//prints out "max"
System.out.println(s1);// prints out "max"
if(s == s1) { // if statement is not executed. Note: i entered the same string.
myNewNode.next = head.next;
head = myNewNode;
}
else {
while(current != null) {
String s2 = current.title;
if(s2 == s1) {
current = new Node(myNewNode);
}
}
}
current = head;
return true;
}
public Node search(Node nodeToSearch) {
current = head;
while(current != null) {
if(current == nodeToSearch) {
Node p = new Node(current);
current = head;
return p;
}
}
return null;
}
public boolean saveToFile(String filename) throws Exception {
Node p = new Node();
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(myFile));
out.writeObject(p);
out.close();
return true;
}
public boolean loadFromFile(String filename) throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(myFile));
head = (Node) in.readObject();
return true;
}
public Node listIterator() {
try{
if(current == head) {
rover = current;
current = current.next;
return rover;
}
else {
rover = current;
current = current.next;
Node p = new Node(rover);
return p;
}
}
catch(NullPointerException e) {
current = head;
return null;
}
}
public Node listIterator2() {
try{
if(current == head) {
rover = current;
current = current.next;
return rover;
}
else {
rover = current;
current = current.next;
return rover;
}
}
catch(NullPointerException e) {
current = head;
return null;
}
}
public boolean equals(Database db) {
Node p;
while(rover != null) {
p = head;
while(p != null) {
if(rover != p)
return false;
p = p.next;
}
rover = rover.next;
}
return true;
}
public String whoIAm() {
ako = "Michael Glenn R. Roquim Jr. !";
return ako;
}
}
You trigger your own NPE:
// vv-- here you set head to null, just before you dereference it to access .title
head = null;
//here, no matter what you enter, this if statement is never executed. Yes, never. even if they are equal.
if(nodeToDelete.title == head.title) {
head = null;
//here, no matter what you enter, this if statement is never executed. Yes, never. even if they are equal.
if(nodeToDelete.title == head.title) {
you set head to null and immidiately after it you try to access it... (head is always null, so head.title will throw NPE)
also:
if(s == s1) { // if statement is not executed. Note: i entered the same string.
use equals()
while comparing string, and not == (because otherwise you are looking for a same exact reference and not the same "string").
one more thing: it seems you will always throw NPE (when deleting) if your element is not in the list (you will not find the element, reach the end of the list which is null, and then try to address an instance variable in it).
I like cutting down code to the essentials so here is a working version which just does what the methods suggest.
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
class MyDatabase {
private final List<Book> titles = new ArrayList<Book>();
public void insert(Book title) {
titles.add(title);
}
public boolean delete(Book title) {
return titles.remove(title);
}
public boolean replace(Book title1, Book title2) {
int pos = titles.indexOf(title1);
if (pos >= 0) {
titles.set(pos, title2);
return true;
}
return false;
}
public Book search(String title) {
for (Book book : titles) {
if (book.title.equals(title))
return book;
}
return null;
}
public void saveToFile(String filename) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
out.writeObject(titles);
out.close();
}
public void loadFromFile(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
titles.clear();
titles.addAll((List) in.readObject());
in.close();
}
public ListIterator<Book> listIterator() {
return titles.listIterator();
}
public boolean equals(Object o) {
return o instanceof MyDatabase && ((MyDatabase) o).titles.equals(titles);
}
public String whoIAm() {
return "Michael Glenn R. Roquim Jr. !";
}
}
class Book {
final String title;
final int year;
Book(String title, int year) {
this.title = title;
this.year = year;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book book = (Book) o;
if (year != book.year) return false;
if (!title.equals(book.title)) return false;
return true;
}
}
Hmm, several problems here.
You set head to null, then promptly reference head.title. This will always throw a null pointer exception. I see someone else pointed that out.
You attemt to compare strings with ==. This won't work, it compares the address of the string, not the contents. Use equals.
When you check if the node matches the head node, you compare the titles. But when you compare to any other node, you do == on the node itself. You shouldn't have two different methods to compare nodes. As noted above, the title==title won't work. node==node might or might not work. How do you get a node to delete? If it is really the same node, i.e. the same object, as the node in the list that you are trying to delete, that's fine. But if it is a node constructed from, say, a user input, and so it will have maybe the same title as a node in the list, but not actually be the same object, this won't work. You probably want to say node.equals(node) and define an equals() function on node.
You set current to head and p to head, then you search starting from current, then you search starting from p. These should give identical results. Why do it twice?
If you don't find the node, you eventually hit a next value equal to null, but you just keep looking, thus generating a null-pointer exception.
As a point of style, it is better to define a variable within a function rather than as a member variable whenever possible.
Finally, may I suggest a little trick: Instead of having special handling for head all over the place, create a "sentinel", a fake node whose next pointer points to head. This really simplifies the code. For example:
class MyLinkedList
{
Node sentinel;
public MyLinkedList()
{
sentinel=new Node();
sentinel.next=null;
}
public void insert(Node myNewNode)
{
// This assumes new nodes must be added at the end. With a single-linked
// list, this requires traversing the entire list to reach the end.
Node current;
/* Note sentinel is never null, so we don't need any special handling here.
If the list is empty, sentinel.next is null, but that doesn't create
a special case.
*/
for (current=sentinel; current.next!=null; current=current.next) ;
current.next=myNewNode;
myNewNode.next=null;
}
public void insertAtStart(Node myNewNode)
{
// If we can add new nodes to the beginning, this is much faster.
myNewNode.next=sentinel.next;
sentinel.next=myNewNode;
}
public boolean delete(Node nodeToDelete)
{
Node current;
for (current=sentinel; current.next!=null; current=current.next)
{
if (current.next.equals(nodeToDelete)
{
current.next=current.next.next;
return true;
}
}
return false;
}
... etc ...
精彩评论