Java: Why is there a NullPointerException when there is no null? [duplicate] - java

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
This is my first time using this site so hopefully this makes sense. I have my code below and when I execute it its giving me a NullPointerException on line 38 in my Library class,
(the line says if (items[i].getTitle() != null && items[i].getTitle().equals(title)) {)
and another NullPointerException on like 29 in my MainMethod class,
(line is if (loaned == true) {).
To check the contents of items[i], after I added an item I had printed in the console to see if it was null and it successfully printed so I am confused as to why the NullPointerExpcetion is present. Any and all help will be greatly appreciated.
public class MediaItem {
private String title;
private String format;
public boolean onLoan;
public String loanedTo;
public String dateLoaned;
MediaItem() {
onLoan = false;
loanedTo = null;
dateLoaned = null;
title = null;
format = null;
}
MediaItem(String title, String format) {
this.title = title;
this.format = format;
}
public String getTitle() {
return this.title;
}
public String setFormat(String format) {
this.format = format;
return this.format;
}
public String getFormat() {
return format;
}
void markOnLoan(String name, String date) {
if (onLoan == true) {
System.out.println(title + " is already on loan to " + loanedTo);
} else {
onLoan = true;
loanedTo = name;
dateLoaned = date;
}
}
void markReturned() {
}
}
import java.util.Scanner;
public class Library {
int numberOfItems = 0;
MediaItem[] items = new MediaItem[100];
int displayMenu() {
Scanner s = new Scanner(System.in);
System.out.println(
"1. Add an item \n2. Mark an item as on loan \n3. List all items \n4. Mark an item as returned \n5. Quit \n\nWhat would you like to do?");
int choice = s.nextInt();
return choice;
}
void addNewItem(String title, String format) {
items[numberOfItems] = new MediaItem(title, format);
numberOfItems++;
}
void markItemOnLoan(String title, String name, String date) {
for (int i = 0; i <= 100; i++) {
if (items[i].getTitle() == title) {
items[i].onLoan = true;
items[i].loanedTo = name;
items[i].dateLoaned = date;
}
}
}
boolean checkIfLoaned(String title) {
char loaned = 'N';
System.out.println(items[0].getTitle());
for (int i = 0; i < 100; i++) {
if (items[i].getTitle() != null && items[i].getTitle().equals(title)) {
if (items[i].onLoan) {
String personName = items[i].loanedTo;
System.out.println(title + " is already on loan to " + personName);
loaned = 'Y';
}
}
}
if (loaned == 'Y') {
return true;
} else {
return false;
}
}
}
import java.util.Scanner;
public class MainMethod {
public static void main(String[] args) {
int choice = 1;
String personName;
String mediaName;
String format;
String loanDate;
Scanner s = new Scanner(System.in);
Library l = new Library();
while (choice != 5) {
choice = l.displayMenu();
switch (choice) {
case 1:
System.out.println("What is the title?");
mediaName = s.nextLine();
System.out.println("What is the format?");
format = s.nextLine();
l.addNewItem(mediaName, format);
break;
case 2:
System.out.println("Which item (enter the title)?");
mediaName = s.nextLine();
System.out.println("Who are you loaning it to?");
personName = s.nextLine();
boolean loaned = l.checkIfLoaned(mediaName);
if (loaned == true) {
break;
}
System.out.println("When did you loan the item?");
loanDate = s.nextLine();
l.markItemOnLoan(mediaName, personName, loanDate);
}
}
}
}

I am assuming this is homework, so I will steer you in the right direction, as opposed to posting code.
You are iterating through a hard-coded value of 100 items in both markItemOnLoan and checkIfLoaned. Just because you declare an array of 100 items, does not mean they are all initialized. Consider altering your loops to iterate through numberOfItems instead of 100. You should also do a check in addNewItem to ensure you won't surpass 100 items.
Related to #1, you do not check if the actual item you are extracting from the array is null, so you're attempt to call a method getTitle on a null Object, naturally throws a NPE.
Side note, in markItemOnLoan, you're incorrectly comparing Strings. The way you compare titles in checkIfLoaned is correct.

it would be better if you post the callstack too. 3 potential errors I can see are :
items[i] might be null. Although you are checking for null on items[X].getTitle()... You don't perform a null check on items[i]
Your for loop goes from 0 to 100. Is it gauranteed that all elements in array from 0-99 index are populated ? Shouldn't you go from 0 to items.length ?
Your array is defined for 100 elements. You are trying to access 101st elements in the for loop (i<=100) should be i < 100.

Why is there a NullPointerException when there is no null?
It cannot happen.
From this we deduce that there is a null. That is simple logic.
If you are going to succeed in debugging a program MUST NOT deny what the evidence tells you.
So where is the null?
if (items[i].getTitle() != null && items[i].getTitle().equals(title)) {
Based on this line alone there are four possible explanations:
items is null
items[i] is null
another thread is changing something ... and you got unlucky.
the getTitle() method is returning something that is not a String or that is not the same String each time.
We can eliminate the first and fourth explanations by reading the code, and the third one is extremely unlikely (even supposing that it is possible).
That leaves the second explanation as the "working hypothesis".

Related

Searching for a String in an ArrayList of Objects

I have been trying to figure this out for hours and I have had no luck doing so,
I'm trying to iterate over my Arraylist<Booking> which utilizes my Booking class file and trying to understand how I'm able to search it for the matching, case-insensitive term.
this is my current method:
private void searchBookings() {
if (bookings.size() <= 0) {
JOptionPane.showMessageDialog(null, "There are no bookings.", "Search Bookings", 3);
} else {
String searchTerm = JOptionPane.showInputDialog(null, "Please input search term: ", "Search Bookings", 3);
for (int i = 0; i < bookings.size(); i++) {
while (!bookings.get(i).getStudent().getName().equalsIgnoreCase(searchTerm)) {
i++;
if (bookings.get(i).getStudent().getName().equalsIgnoreCase(searchTerm)) {
String output = String.format("%-30s%-18s%-18b$%-11.2f\n", bookings.get(i).getStudent(), bookings.get(i).getLessons(), bookings.get(i).isPurchaseGuitar(), bookings.get(i).calculateCharge());
this.taDisplay.setText(heading + "\n" + output + "\n");
}
}
}
}
JOptionPane.showMessageDialog(null, "There is no booking with that name.", "Search Bookings", 3);
}
I know it's messy but, just trying to make do.
I am trying to retrieve the name of the booking as I am searching by name as well as provide an error message if that names does not exist, to do that I must
use bookings.getStudent().getName() I have had some luck as I can return the value but now I am not able to provide my error message if I do not find it. Any help is appreciated.
package com.mycompany.mavenproject1;
public class Booking {
private Student student;
private int lessons;
private boolean purchaseGuitar;
// CONSTANTS
final int firstDiscountStep = 6;
final int secondDiscountStep = 10;
final int tenPercentDiscount = 10;
final int twentyPercentDiscount = 5;
final double LESSON_COST = 29.95;
final double GUITAR_COST = 199.00;
double LESSON_CHARGE = 0;
final int MINIUMUM_LESSONS = 1;
public Booking() {
}
public Booking(Student student, int lessons, boolean purchaseGuitar) {
this.student = new Student(student.getName(), student.getPhoneNumber(), student.getStudentID());
this.lessons = lessons;
this.purchaseGuitar = purchaseGuitar;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public int getLessons() {
return lessons;
}
public void setLessons(int lessons) {
this.lessons = lessons;
}
public boolean isPurchaseGuitar() {
return purchaseGuitar;
}
public void setPurchaseGuitar(boolean purchaseGuitar) {
this.purchaseGuitar = purchaseGuitar;
}
public double calculateCharge() {
double tempCharge;
if (lessons < firstDiscountStep) {
LESSON_CHARGE = (lessons * LESSON_COST );
} else if (lessons < secondDiscountStep) {
tempCharge = (lessons * LESSON_COST) / tenPercentDiscount;
LESSON_CHARGE = (lessons * LESSON_COST) - tempCharge;
} else {
tempCharge = (lessons * LESSON_COST) / twentyPercentDiscount;
LESSON_CHARGE = (lessons * LESSON_COST) - tempCharge;
}
if (isPurchaseGuitar()) {
LESSON_CHARGE += GUITAR_COST;
}
return LESSON_CHARGE;
}
#Override
public String toString() {
return student + ","+ lessons + "," + purchaseGuitar +"," + LESSON_COST;
}
}
If I understood you correctly, you are searching for a given student name in your collection of bookings. And if it is present, set a formatted text.
First of all, use a for-each loop, because you don't use the index.
Secondly, return from the for-each loop, when you found your student.
private void searchBookings() {
if (bookings.size() <= 0) {
JOptionPane.showMessageDialog(null, "There are no bookings.", "Search Bookings", 3);
} else {
String searchTerm = JOptionPane.showInputDialog(null, "Please input search term: ", "Search Bookings", 3);
for (final Booking booking : bookings) // for-each
{
if (booking.getStudent().getName().equalsIgnoreCase(searchTerm))
{
String output = booking.getFormattedOutput();
this.taDisplay.setText(heading + "\n" + output + "\n");
return; // break out of the loop and method and don't display dialog message
}
}
}
JOptionPane.showMessageDialog(null, "There is no booking with that name.", "Search Bookings", 3);
}
Then there are multiple other things, which you could improve.
Don't get all the data from a booking just to format it externally. Let the Booking class handle the formatting and return you the string you desire. (move the formatting in a function inside the Booking class)
Instead of recreating a Student you receive in your Booking constructor, make the Student class immutable, and then you can just reuse the object provided.
Try also making the Booking class immutable. You provided some setters, but do you really want to change the student in a booking? Or would you rather create a new booking for the other student?
The calculteCharge method could be stateless. Just get the LESSON_CHARGE value and hold it in a local variable. Your method would also get threading-proof.
Make your constants final and better yet make them members of the class (by adding the static modifier) instead of every member.
Lastly, representing a money amount with a floating (double is better but not good either) number, you will run into funny situations. Try this calculation: 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 for example.
One way would be to create a Money class which holds the value in cents as an integer. And when you want to display the amount you can divide it by 100 and format it accordingly. That way, you can also restrict it become negative.
PS: Sometimes we desperately try to find a solution that we don't give ourselves some rest. After a little break, you might recognize the problem. Oh and try debugging with breakpoints. Or this, if you use IntelliJ IDEA (which I would highly recommend, the community edition is free).
You're re-incrementing your counter variable, which is really not going to help. Try the following:
private void searchBookings() {
if (bookings.size() <= 0) {
JOptionPane.showMessageDialog(null, "There are no bookings.", "Search Bookings", 3);
} else {
String searchTerm = JOptionPane.showInputDialog(null, "Please input search term: ", "Search Bookings", 3);
boolean studentFound = false;
for (int i = 0; i < bookings.size(); i++) {
if (bookings.get(i).getStudent().getName().equalsIgnoreCase(searchTerm)) {
String output = String.format("%-30s%-18s%-18b$%-11.2f\n", bookings.get(i).getStudent(),
bookings.get(i).getLessons(), bookings.get(i).isPurchaseGuitar(),
bookings.get(i).calculateCharge());
this.taDisplay.setText(heading + "\n" + output + "\n");
studentFound = true;
break;
}
}
}
if (!studentFound) {
JOptionPane.showMessageDialog(null, "There is no booking with that name.", "Search Bookings", 3);
}
}

Compiler not recognizing that class string value is equal to another String value [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 2 years ago.
public class Station {
String name;
boolean pass;
int distance;
// method to create a new Station taking the arguments of the name,pass and distance in the parameter
public static Station createStation(String name, boolean pass, int distance) {
}
// Array list containing all the Stations in London we will use
static Station[] StationList = {createStation("Stepney Green", false, 100), createStation("Kings Cross", true, 700), createStation(
"Oxford Circus", true, 200)};
public static String infoAboutStation(Station station) {
String message;
if (station.pass)
message = //string message
else
message = //string message
return message;
}
public static String checkInfo(String stationName){
String info = null;
for(Station station : StationList){
if(stationName == station.name) { //it does not recognise it to be the same for some reason
info = stationName + infoAboutStation(station);
}
else
info = stationName + " message ";
}
return info;
}
public static void printInfo(){
Scanner scanner = new Scanner(System.in);
System.out.println("How many... ");
int totalResponses = Integer.parseInt(scanner.nextLine());
String choice;
for(int i = 0; i < totalResponses; ++i){
System.out.println("Enter a station: ");
choice = scanner.nextLine();
System.out.println(checkInfo(choice));
}
}
// psvm(String[] args)
}
So the program runs fine but when we use "Stepney Green", "Kings Cross", "Oxford Circus" as the input for choice at checkinfo(choice), it does not recognise it to be the same for stationName == station.name in the method checkInfo(stationName //choice)
Intellij debugger reads this at stationName == station.name
-StationList = {Station[3]#980} -> 0 = {Station#994} 1 = {Station#997} 2 = {Station#998}
-static -> StationList = {Station[3]#980}
-stationName = "Stepney Green" value = {byte[13]#996} coder = 0 hash = 0 hashisZero = 0
-info = null
-station = {Station#994} -> name = "Stepney Green", pass = false, distance = 100
-station.name = "Stepney Green" -> value = {byte[13]#999] rest is zero
Beside the statement it says stationName: "Stepney Green" station: Station#994. Instead of printing out stationName + infoAboutStation it goes to the else station and prints "Stepney Green is not a London Underground Station". I am so puzzled as to why. Also if you don't mind helping me as to making this code a little more efficient and better.
You should compare String using equals()
Replace this
if(stationName == station.name)
by
if(stationName.equals(station.name))
FIXED changed to
for(Station station : StationList){
if(stationName.equals(station.name)) {
info = stationName + infoAboutStation(station);
break;
}
}
Thanks for the help

Search 2D ArrayList by user input & display row in Java

I'm having a little trouble with a fairly simple assignment, but couldn't find an answer here that seemed to work.
I need to have a 2D ArrayList that contains staff data, and then be able to run a separate function that allows the user to input a staff member's name, searches the ArrayList for that name, and if it exists, display the full row of data.
Here's what I've got so far:
The ArrayList
List<List<String>> staffArrayString = new ArrayList<>();
staffArrayString.add(Arrays.asList("Steven George", "12 York Road", "07123456678", "Permanent", "York", "27000/yr"));
staffArrayString.add(Arrays.asList("Rina Veyer", "20 Leeds Road", "08987987765", "Part Time", "Leeds", "10/hr"));
staffArrayString.add(Arrays.asList("Brian Lym", "13 Bradford Road", "07123234345", "Permanent", "Bradford", "27000/yr"));
The search function
public void staffNameSearch() {
System.out.println("Enter name of staff member:");
String staffName = in.next();
boolean found = false;
int row = 0;
for (int i = 0; i < staffArrayString.size(); i++) {
for (int j = 0; j < staffArrayString.get(i).size(); j++) {
if (staffArrayString.get(i).get(j).equals(staffName)) {
row = staffArrayString.get(i).size();
found = true;
}
}
}
if (found = true) {
System.out.print(staffArrayString.get(row) + " ");
}
}
I'm currently getting an output of 'Exception in thread "main" java.lang.IndexOutOfBoundsException' at the print line on the end there, but I can't for the life of me work out why. I'd appreciate any advice on this (especially if it's some obvious and stupid mistake on my part!).
The error is occuring because you are setting row to something unrelated to the row counter. When you discover the row (variable i) which has the name in the jth element, set row=i.
Be careful about if (found = true) - it is incorrect; prefer:
a) if (found)
b) if (found == true)
For efficiency, include && !found in the for loops so they exit as soon as you find something.
You can use for each loop for simpler.
System.out.println("Enter name of staff member:");
String staffName = in.next();
boolean found = false;
String[] foundArray;
for(String[] staffArray: staffArrayString){
for(String str : staffArray){
if(str.equals(staffName)){
foundArray = staffArray;
found = true;
break;
}
}
}
if (found == true) {
System.out.print(foundArray + " ");
}
You might be able to simplify the code a little bit by using a Map and a Staff class.
For example, the Staff class
public class Staff{
String name;
String address;
String id; // ?
boolean permanent; // Or a enum if there are more than 2 values
String city; // ?
int payrate;
boolean hourly;
#Override
public String toString(){ // Easily convert the class to a String
return String.format("%s %s %s %s %s $%d/%s",
name,
address,
id,
permanent ? "Permanent" : "Part-time",
city,
payrate,
hourly ? "hr" : "yr");
}
}
And for the code to read it
private Map<String, Staff> staffDirectory; // String is the name in lowercase
public void staffNameSearch() {
// Code
if(staffDirectory.containsKey(staffName)){ // Make sure staffName is lowercase
System.out.print(staffDirectory.get(staffName) + " ");
} else {
System.out.println("Name not found");
}
}
This way you can avoid using loops and get O(1) efficiency.

Cannot read text file into array and write to text file again

This my whole code.
I want to make a simple program that will read a
text file and put it to array then write it to the
same text file,
also can add and delete the existing input and my input.
Problem
The delete and writer part seems not working, only blank text file when I run the code
These are the error after I select the exit.
java.lang.NullPointerException at ContactList.writer(ContactList.java:51) at
ContactListDriver.main(ContactListDriver.java:73) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at
java.lang.reflect.Method.invoke(Unknown Source) at
edu.rice.cs.drjava.model.compiler.JavacCompiler.runCommand(JavacCompiler.java:27‌​2)
public class Contact {
//Each contact stores the name, phone number, and email address
private String name;
private String number;
private String email;
public Contact(String name, String number, String email)
{
this.name = name;
this.number = number;
this.email = email;
}
public String getName()
{
return name;
}
public String getNumber()
{
return number;
}
public String getEmail()
{
return email;
}
public void setName(String name)
{
this.name = name;
}
public void setNumber(String number)
{
this.number = number;
}
public void setEmail(String email)
{
this.email = email;
}
}
class for processing the inputs.
import java.io.*;
import java.lang.*;
import java.util.*;
public class ContactList {
public Contact[] myContacts;
public static final int MAX = 100;
private int numContacts;
public ContactList()
{
myContacts = new Contact[MAX];
numContacts = 0;
}
public void addContact(String name, String number, String email)
{
Contact c = new Contact(name, number, email);
myContacts[numContacts] = c;
numContacts++;
}
public void deleteContact(String name)
{
for ( int i = 0; i <= numContacts-1 ; i++){
if( name == myContacts[i].getName())
{
myContacts[i] = null;
break;
}
}
numContacts--;
}
public void writer(){
String x = "MyContacts.txt";
try {
PrintWriter outputs = new PrintWriter(x);
for( int i=0; i < myContacts.length; i++)
{
Contact c = myContacts[i];
if(c!=null){ // check if c is null before writing to file
outputs.println(""+c.getName()+" "+c.getNumber()+" "+c.getName());
outputs.flush();
}
}
outputs.close();
}catch (IOException e) {
e.printStackTrace();
}
catch(NullPointerException ex){
}
}
public void displayContacts()
{
int i;
for(i=0; i < myContacts.length; i++)
{
Contact c = myContacts[i];
if(null != c){
System.out.println("Name: " + c.getName());
System.out.println("Number: " + c.getNumber());
System.out.println("Email: " + c.getEmail());
System.out.println("------------------------------------");
}
}
}
}
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
The Driver....
public class ContactListDriver {
public static void main(String[] args) throws FileNotFoundException
{
ContactList cList = new ContactList();
File in = new File("MyContacts.txt");
Scanner sc = new Scanner(in);
int option;
char again = 'n';
String name = null;
String number = null;
String email = null;
while(sc.hasNext())
{
//read one line from text file
String entry = sc.nextLine();
//System.out.println(entry);
String[] con = entry.split("\\s+");
//System.out.println(con[0] + " " + con[1] + " " + con[2]);
cList.addContact(con[0], con[1], con[2]);
}
Scanner userIn = new Scanner(System.in);
do{
displayOptions();
option = userIn.nextInt();
switch(option)
{
case 1:
System.out.println(" Name > ");
name = userIn.next();
System.out.println(" Number > ");
number = userIn.next();
System.out.println(" Email Address > ");
email = userIn.next();
cList.addContact(name, number, email);
break;
case 2:
//delete contact
System.out.println("Contact Name > ");
name = userIn.next();
cList.deleteContact(name);
break;
case 3:
//display contact
cList.displayContacts();
break;
case 4:
cList.writer();
System.out.println(" are you sure ? press y ");
String x = userIn.next();
again = x.charAt(0);
break;
}
}while( again == 'n' );
}
private static void displayOptions() {
System.out.println("(1) Add");
System.out.println("(2) Delete");
System.out.println("(3) Show Contacts");
System.out.println("(4) Exit");
}
}
One problem I see is:
You have a extra break; statement inside deleteContact(String name) function
and String comparision name == myContacts[i].getName() should be name.equals(myContacts[i].getName())
public void deleteContact(String name)
{
for ( int i = 0; i <= numContacts-1; i++){
if( name.equals( myContacts[i].getName()))// string comparison uses equals();
{
myContacts[i] = null;
numContacts--; // this line should be inside of if condition
break;
}
// break; No need of breaking the loop here
}
}
Another problem is at writer() function
public void writer(){
String x = "MyContacts.txt";
try {
PrintWriter outputs = new PrintWriter(x);
for( int i=0; i < myContacts.length; i++)
{
Contact c = myContacts[i];
if(c!=null){ // check if c is null before writing to file
outputs.println(""+c.getName()+" "+c.getNumber()+" "+c.getName());
outputs.flush();
}
}
outputs.close();
}catch (IOException e) {
e.printStackTrace();
}
catch(NullPointerException ex){ // Or just catch the NPE
}
You have declared and initialized the Contact array of size MAX. but,it seems to be that you haven't initialized the elements though. i.e. c is null in the below code
Contact c = myContacts[i];
outputs.println(""+c.getName()+" "+c.getNumber()+" "+c.getName());
outputs.flush();
myContacts[i] should return a Contact instance. As said by Meno, there are lot of other problems in your code. You have to always cover all the possible scenarios while writing the code.
Most importantly you need to fix the ContactList class. It is inserting new elements into the last index, and deleting at any location using the name.
For example, let's say the ContactList has three elements in it at 0, 1 and 2 indexes. So numContacts is set to 3.
Now ContactList has elements as:
[0]C0, [1]C1, [2]C2, [3]null, ...
Then if the contact at 0 index is deleted (set to null), then numContacts is set to 2.
Now the ContactList has elements as:
[0]null, [1]C1, [2]C2, [3] null, ...
A new insert will be added to the index 2, and it will override the C2 value.
Simplest solution is to use an ArrayList instead of an array.
As others have mentioned there are few more issues to fix, but above is the most important in my opinion.
There are many issues with your code so not easy to say where to begin.
First: Your public void deleteContact(String name)-method is broken. It compares Strings using == instead of equals(). And worse: It creates null pointers mid in your array which will cause problems in your writer()-method.
Second: Why do you use arrays? You should use java.util.ArrayList which offers out-of-the-box implementations for adding, getting and deleting contacts.
Third: If you are missing your text file, you might have overlooked it because of missing path so you don't know where to look for this file. So please add a full path to file name.
Fourth: I would also use scanner.hasNextLine() instead of scanner.hasNext() if you then call scanner.nextLine().
Since you said you are not allowed to use ArrayList you should study its source code especially for removing elements. It does not only nullify the array bucket, but also to shift all following elements one index backwards so you don't have any null gap until the index given by element count. And two breaks in deleteContact()-method are really not necessary.

Logic of deleting in Java

I cant figure out how to start a method to delete a specific entry stored in an array...
I used to do this:
public void deleteEntry() {
SName = JOptionPane.showInputDialog("Enter Name to delete: ");
for (int i = 0; i < counter; i++) {
if (entry[i].getName().equals(SName)) {
JOptionPane.showMessageDialog(null, "Found!");
entry[i] = null;
}
}
}
but I was advised not to assign the entry[i] to null because it will ruin my entries...
I have no idea how to code it in another way...
What should I need to do is:
I need to delete a specific entry from an array
please help...
also... its output was error it says:
Exception in thread "main" java.lang.NullPointerException
at AddressBook.viewAll(AddressBook.java:62)
at AddressBook.main(AddressBook.java:36)
Java Result: 1
This is my code in my main program:
public class AddressBook {
private AddressBookEntry entry[];
private int counter;
private String SName;
public static void main(String[] args) {
AddressBook a = new AddressBook();
a.entry = new AddressBookEntry[100];
int option = 0;
while (option != 5) {
String content = "Choose an Option\n\n"
+ "[1] Add an Entry\n"
+ "[2] Delete an Entry\n"
+ "[3] Update an Entry\n"
+ "[4] View all Entries\n"
+ "[5] View Specific Entry\n"
+ "[6] Exit";
option = Integer.parseInt(JOptionPane.showInputDialog(content));
switch (option) {
case 1:
a.addEntry();
break;
case 2:
a.deleteEntry();
break;
case 3:
a.editEntry();
break;
case 4:
a.viewAll();
break;
case 5:
a.searchEntry();
break;
case 6:
System.exit(1);
break;
default:
JOptionPane.showMessageDialog(null, "Invalid Choice!");
}
}
}
public void addEntry() {
entry[counter] = new AddressBookEntry();
entry[counter].setName(JOptionPane.showInputDialog("Enter name: "));
entry[counter].setAdd(JOptionPane.showInputDialog("Enter add: "));
entry[counter].setPhoneNo(JOptionPane.showInputDialog("Enter Phone No.: "));
entry[counter].setEmail(JOptionPane.showInputDialog("Enter E-mail: "));
counter++;
}
public void viewAll() {
String addText = " NAME\tADDRESS\tPHONE NO.\tE-MAIL ADD\n\n";
for (int i = 0; i < counter; i++) {
addText = addText + entry[i].getInfo() + "\n";
}
JOptionPane.showMessageDialog(null, new JTextArea(addText));
}
public void searchEntry() {
int notfound = 0;
SName = JOptionPane.showInputDialog("Enter Name to find: ");
for (int i = 0; i < counter; i++) {
if (entry[i].getName().equals(SName)) {
JOptionPane.showMessageDialog(null, entry[i].getInfo2());
break;
} else {
notfound++;
}
}
if (notfound != 0) {
JOptionPane.showMessageDialog(null, "Name Not Found!");
}
notfound = 0;
}
public void editEntry() {
int notfound = 0;
SName = JOptionPane.showInputDialog("Enter Name to edit: ");
for (int i = 0; i < counter; i++) {
if (entry[i].getName().equals(SName)) {
entry[i] = new AddressBookEntry();
entry[i].setName(JOptionPane.showInputDialog("Enter new name: "));
entry[i].setAdd(JOptionPane.showInputDialog("Enter new add: "));
entry[i].setPhoneNo(JOptionPane.showInputDialog("Enter new Phone No.: "));
entry[i].setEmail(JOptionPane.showInputDialog("Enter new E-mail: "));
break;
} else {
notfound++;
}
}
if (notfound != 0) {
JOptionPane.showMessageDialog(null, "Name Not Found!");
}
notfound = 0;
}
public void deleteEntry() {
SName = JOptionPane.showInputDialog("Enter Name to delete: ");
for (int i = 0; i < counter; i++) {
if (entry[i].getName().equals(SName)) {
JOptionPane.showMessageDialog(null, "Found!");
entry[i] = null;
break;
}
}
}
}
Assigning the values to null is going to be the easiest practice. If you're really picky, you could resize the array, but that would be rather pointless. Just keep a separate size counter and decrement it each time you set something to null.
Another reason you're getting a null pointer exception is that you have to consider what's happening when you're replacing values in your array with null but still iterating by counter. You're going to be left with holes in your array upon deletion. The first solution would be to bypass null values altogether, and just shift your array down (somewhat of an expensive operation). The second would be to alter your methods to take those null values into consideration. Example:
public void viewAll() {
String addText = " NAME\tADDRESS\tPHONE NO.\tE-MAIL ADD\n\n";
int nonNull = 0;
for (int i = 0; i < entry.length; i++) {
if (entry[i] != null) {
addText = addText + entry[i].getInfo() + "\n";
nonNull++;
}
if (nonNull == counter) break;
}
JOptionPane.showMessageDialog(null, new JTextArea(addText));
}
I don't have a compiler on this computer, so consider it more of psuedo-code. But the idea is that the counter is only keeping track of how many non-null values you have in your address book, and that these null values could be in random places of your array. I added the nonNull integer as a local counter to keep track of how many values you've encountered that aren't null (so you aren't forced to run through the entire address book). Then, I added the if statement to ensure that the value at entry[i] isn't a null value (trying to invoke getInfo() on a null value is what's giving you that error). Lastly, I added the if statement to break the loop if you've encountered all of the non-null values you have stored. Hope this helps. (Also it may be worth considering a LinkedList to eliminate the null values all together).
Actually, for simplicity's sake, you probably are much better off using a LinkedList, unless you are required to use an array, since you would need to alter all of your methods to take null spaces in your array into account. Assuming you're familiar with LinkedLists of course.
Arrays are immutable. You can change the value for a particular index in the array but you can't change the array size itself. To "delete", you could do:
myArray[index] = null;
And just treat null values as unset/deleted entries.
Assigning to null (currently what you are doing) is the proper thing to do. That will eliminate the reference to the object at that index and allow it to be garbage collected.
Replace entry[i] = null; with this:
System.arraycopy(entry, i + 1, entry, i, counter - i - 1);
--counter;
entry[counter] = null; // optional; helps with garbage collection
--i; // required to not skip the next element
(I'm assuming here that counter is the number of valid entries in entry. This will leave no null entries among the first counter elements of entry (assuming that there weren't any to start with).
Further thought: If you need the array length to always match the number of valid entries, you'll have to re-allocate the array and copy the values over. Just use arraycopy to copy entries from 0 through i-1 and from i+1 to counter-1 into the new array and then assign it to entry. This isn't particularly efficient and is best avoided if possible.
Better to this is List which has remove() method. But if you really want use Array I recommend you change Array to List and then remove all values, after it you can always change List to Array
import javax.swing.JOptionPane;
public class Test {
private static User[] entry = new User[] { new User("Gil"),
new User("Bil"), new User("John") };
public static void main(String... args) {
final Test test = new Test();
test.deleteEntry();
for (int index = 0; index < entry.length; index++) {
User user = entry[index];
if (user != null)
System.out.println(entry[index]);
}
}
public void deleteEntry() {
String SName = JOptionPane.showInputDialog("Enter Name to delete: ");
for (int index = 0; index < entry.length; index++) {
if (entry[index].getName().equals(SName)) {
JOptionPane.showMessageDialog(null, "Found!");
entry[index] = null;
break;
}
}
}
private static class User {
private String name;
public User(String name) {
this.name = name;
}
/**
* #return the name
*/
public String getName() {
return name;
}
#Override
public String toString() {
return name;
}
}
}

Categories