This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed last year.
I'm still new to programming and I want to make a program that will take the food order from user until the user presses "n" to stop. But I can't seem to make it work like I want it to.
I want my output to be like this.
Buy food: Burger
Order again(Y/N)? y
Buy Food: Pizza
Order again(Y/N)? n
You ordered:
Burger
Pizza
But my output right now is this.
Buy food: Burger
Order again(Y/N)? y
Buy food: Pizza
Order again(Y/N)? n
You ordered:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Array.getFoodName()" because "food_arr2[i]" is null
at Food.main(Food.java:50)
Here is my code:
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
Food food = new Food();
Array[] food_arr;
boolean stop = false;
String foodName;
int k = 1;
int j = 0;
while(stop == false) {
food_arr = new Array[k];
System.out.print("Buy food: ");
foodName = s.next();
food_arr[j] = new Array(foodName);
food.setFoodArray(food_arr);
System.out.print("Order again(Y/N)? ");
String decide = s.next();
if(decide.equalsIgnoreCase("y")) {
k++;
j++;
}
else if(decide.equalsIgnoreCase("n")) {
stop = true;
}
}
Array[] food_arr2 = food.getFoodArray();
for (int i = 0; i < food_arr2.length; ++i) {
System.out.println("\nYou ordered: ");
System.out.println(food_arr2[i].getFoodName()); //This line is the error according to my output
}
}
I don't know how to fix this and I was hoping for someone to help me.
I think I see what you are trying to do with the k value setting the size of the array you are using.
However, with each iteration of the while loop:
food_arr = new Array[k];
Will create a new empty array each time!
So, for example, on the second iteration
food.setFoodArray(food_arr);
Will set foods array as something like [null, "Pizza"]
Even if this did work, creating a new array each time is not a very efficient method.
I would strongly recommend using a different, dynamically allocated data structure such as an ArrayList and defining it outside the scope of the while loop.
ArrayList<Food> food_arr = new ArrayList<Food>()
// Note that I'm just guessing the data type here - I can't see what you are actually using!
while(stop == false) {
System.out.print("Buy food: ");
foodName = s.next();
food_arr.add(foodName)
// etc, etc
}
food.setFoodArray(food_arr)
// ! Note: You will need to convert the array list into an array
// ! or change the data struture in the Food class
// etc, etc
However, this is just the first solution that popped into my head, check out different kinds of data structures and think about how else you could design this program yourself!
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
am trying to find a way to remove an object from a list based on a condition, the object is a patient that have an age attribute, i want to remove every patient that is older than 25 age from a list, the code consist of 4 lists that is categorized based on certain info any way here is my code:
public static void main(String[] args) {
// TODO code application logic here
Scanner in = new Scanner(System.in);
Scanner kb = new Scanner(System.in);
boolean flag = true;
System.out.print("Enter number of patients: ");
int n = in.nextInt();
AList patients = new AList(n); //All Patients
AList Apatients = new AList(); //category "A" Patients
AList Bpatients = new AList(); //category "B" Patients
AList Cpatients = new AList(); //category "C" Patients
//Add Patients to the list:
for(int i =0; i < n ; i++){
Patients p = new Patients();
System.out.print("Enter Patient name: ");
p.name = kb.nextLine();
System.out.print("Enter Patient ID: ");
p.id = in.nextInt();
System.out.print("Enter Patient Age: ");
p.age = in.nextInt();
flag = true;
while(flag){
System.out.print("Enter Patient Category: ");
p.category = kb.nextLine();
System.out.println("\n\n");
if(p.category.equals("a") || p.category.equals("A")){
Apatients.add(p);
flag = false;
}
else if(p.category.equals("b") || p.category.equals("B")){
Bpatients.add(p);
flag = false;
}
else if(p.category.equals("c") || p.category.equals("C")){
Cpatients.add(p);
flag = false;
}
else{
System.out.println("Wrong Entry...! Try Again");
}
}
patients.add(p);
}
//Display all patients:
System.out.println("All Patients information : ");
patients.display();
System.out.println("Category A Patients : ");
Apatients.display();
System.out.println("Category B Patients : ");
Bpatients.display();
System.out.println("Category C Patients : ");
Cpatients.display();
//From the list for A category remove each patient with age > 25 year:
for(int i=0; i < Apatients.getLength();){
// here is my problem how to iterate the list and check for any patient age > 25 to remove it?
}
}
You have many, many bugs in this code.
2 scanners
You should have only one Scanner object. Why do you have both kb and in? Delete one.
mixing nextLine and nextAnythingElse
You can't mix those. The usual thing to do is to never use nextLine(); to read a line of text, just use next(). This does require that you update the scanner's delimiter; immediately after making the scanner object, call in.useDelimiter("\r?\n"); on it.
AList isn't a thing
Whatever might 'AList' be? It's not in core java and it doesn't sound like it is required here; just use ArrayList<Patient> instead
naming a class with a plural name.
Clearly a single Patients instance represents a single patient, therefore, you should call it Patient, because what you have is clearly confusing you.
You're breaking with convention.
thisIsAVariableName, ThisIsATypeName, THIS_IS_A_CONSTANT. That should be aPatients, not APatients. This makes your code hard to read, and given that you're using a community resource (Stack Overflow), that's not good.
Your actual question
Given that AList is not a thing and you didn't paste it, it is not possible for anybody on SO to answer this question. Update the question and include the API of AList, or stop using it (there is no reason to use this, unless it is mandated because this is homework, in which case, you should ask your teacher for help on this; they get paid, and are the ones who are supposed to support this AList class you're using). Had you been using ArrayList, there are a number of ways to do this. But first a concern: If you loop through each item by way of 'index', then removing an element shifts all indexes down by one, which makes the math complicated. One extremely easy way out of that dilemma is to loop through the list backwards to forwards, because then the shifting of indices doesn't have an impact.
Option #1: Iterators
var it = aPatients.iterator();
while (it.hasNext()) {
Patient p = it.next();
if (p.getAge() > 25) it.remove();
}
Option #2: Backwards loop
for (int i = aPatients.size() - 1; i >= 0; i--) {
if (aPatients.get(i).getAge() > 25) aPatients.remove(i);
}
Option #3: removeIf
aPatients.removeIf(pat -> pat.getAge() > 25);
I am creating a project where the user enters names of multiple sports teams. The user is not allowed to enter the same name of a team twice. I can't figure out how to compare elements of an array. I tried to use a while loop with equals but I don't think it's the right way.
for(int i = 0; i<tabEquipe.length;i++){ // tabEquipe is the table content of the teams that the user enters.
System.out.println("Entrez les noms des equipes: "); // Asks user to enter team names.
rep2 = a.nextLine();
tabEquipe[i] = rep2;
while(tabEquipe[i].equals(tabEquipe[i])){
}
}
That's confusing, so I assume you have already a new user you want to add, and it seems you can compare users with equals. If there's a new user newUser then it could look like this:
boolean found = false;
for(int i = 0; i < tabEquipe.length; i++){
if (tabEquipe[i].equals(newUser))
{
found = true;
break;
}
}
or, shorter:
boolean found = Arrays.asList(tabEquipe).contains(newUser);
You can use a HashSet to store the names of teams in such a manner that the check if a new name was already used happens very efficiently. For example:
...
Set<String> teamNamesSet = new HashSet<>();
for (int i = 0; i < teamNames.length; i++) {
...
// Checking if a team name was already used
while (teamNamesSet.contains(name)) {
// Show some error message, request input again, etc.
}
// Adding a new team name to the set
teamNamesSet.add(name);
// Adding a new team name also to the array you need
teamNames[i] = name;
}
The great advantage of this approach is that the check if a name is already in a HashSet takes a constant time (O(1)). Using a for loop to check has a linear complexity (O(n)).
double pullPrice(String input){
if(input.length() < 3){
System.out.println("Error: 02; invalid item input, valid example: enter code here'milk 8.50'");
System.exit(0);
}
char[] inputArray = input.toCharArray();
char[] itemPriceArray;
double price;
boolean numVal = false;
int numCount = 0;
for(int i = 0; i <= inputArray.length-1; i ++){
//checking if i need to add char to char array of price
if(numVal == true){
//adding number to price array
itemPriceArray[numCount] = inputArray[i];
numCount++;
}
else{
if(inputArray[i] == ' '){
numVal = true;
//initializing price array
itemPriceArray = new char[inputArray.length - i];
}
else{
}
}
}
price = Double.parseDouble(String.valueOf(itemPriceArray));
return price;
}
Problem: attempting to pull the sequence of chars after white space between 'milk 8.50' as input. Initialization error occurs because I am initializing char array inside an if else statement that will initialize the array if it finds whitespace.
Question: since I don't know my char count number until I find a whitespace is there another way I can initialize? Does the compiler not trust me that I will initialize before calling array.
Also, if I am missing something or there are better ways to code any of this please let me know. I am in a java data structures class and learning fundamental data structures but would also like to focus on efficiency and modularity at the same time. I also have a pullPrice function that does the same thing but pulls the item name. I would like to combine these so i don't have to reuse the same code for both but can only return items with same datatype unless I create a class. Unfortunately this exercise is to use two arrays since we are practicing how to use ADT bags.
Any help is greatly appreciated?
Try something like this:
double pullPrice(String input)
{
try
{
// Instantiate a new scanner object, based on the input string
Scanner scanner = new Scanner(input);
// We skip the product (EG "milk")
String prod = scanner.next();
// and read the price(EG 8.5)
double price = scanner.nextDouble();
// We should close the scanner, to free resources...
scanner.close();
return price;
}
catch (NoSuchElementException ex)
{
System.out.println("Error: 02; invalid item input, valid example: enter code here 'milk 8.50'");
System.exit(0);
}
}
If you are sure that you program will get only proper input data then just initialize your array with null:
char[] itemPriceArray = null;
The main problem why the compiler is complaining - what happens if your program accesses uninitialized variable (for instance with wrong input data)? Java compiler prevents this kind of situations completely.
I will add to the other answers,
since you can't change the size of an array once created. You either have to allocate it bigger than you think you'll need or accept the overhead of having to reallocate it needs to grow in size. When it does you'll have to allocate a new one and copy the data from the old to the new:
int oldItems[] = new int[10];
for (int i=0; i<10; i++) {
oldItems[i] = i+10;
}
int newItems[] = new int[20];
System.arraycopy(oldItems, 0, newItems, 0, 10);
oldItems = newItems;
char[] itemPriceArray = new char[inputArray.length];
This is a homework question so preferably I would like to write as much code as possible, just need a pointer.
I have a class called Sandwich that has a Method to set a main Ingredient and a few other things -
public class Sandwich {
private String mainIngredient, bread;
String getMainIngredient(){
return mainIngredient;
}
void setMainIngredient(String mainIng){
mainIngredient = mainIng;
}
void setBread(String dough){
bread = dough;
}
void setPrice(double cost){
price = cost;
}
Now in another class TestSandwich I've initialized an Array, as part of the question;
Sandwich[] sandwiches = new Sandwich[5];
Now what I need to do is loop through and assign a value to mainIngredient and bread each time.
I think I would want to do something along the lines of this but I'm not really sure how to do it correctly.
for(int i = 0; i < 5; i++){
System.out.println("Insert a main ingredient");
String userInput = sc.next();
sandwiches[i].setBread(userInput);
System.out.println("Insert a bread");
userInput = sc.next();
sandwiches[i].setMainIngredient(userInput);
System.out.println(sandwiches[i].getMainIngredient());
System.out.println("");
}
The main issue is - sandwiches[i].setMainIngredient(userInput);
Im not really experienced with arrays and methods such as these so any help with the correct syntax would be great.
Thanks
Sandwich[] sandwiches = new Sandwich[5]; creates an array of 5 null references.
You need to initialise each element yourself; in your loop write
sandwiches[i] = new Sandwich();
else you'll get NullPointerExceptions. Once you've done that you can call the setting methods as you currently do. Going forward, you could declare a two argument constructor taking the bread and main ingredient as arguments. That's better style since (i) you avoid setters and (ii) the object being in an ill-defined state between construction and use.
Sandwich[] sandwiches = new Sandwich[5];
This allocates an array to hold 5 sandwiches, but it doesn't create any sandwiches. Just the array. You're on the right track to create the sandwiches in a loop.
When you write this loop, instead of iterating until 5, it's better to use sandwiches.length, so that if you want 10 instead of 5 sandwiches, you can change the number in one place instead of 2. It will be safer and less error-prone:
for (int i = 0; i < sandwiches.length; ++i) {
// TODO: get the ingredients from user
// ready to create the sandwich, yum yum
Sandwich sandwich = new Sandwich();
sandwich.setBread("...");
sandwich.setMainIngredient("...");
sandwiches[i] = sandwich;
}
Note: The source codes include multiple classes, so for the sake of your time, I will not post it, but will give you context. Please forgive if I can't explain well. I have been working on this a lot and my explanation makes sense to me but may not make sense to others.
I have a task to determine what category user input belongs into. For example, if a user inputs: I love dogs and cats.
The program will output that the top 2 categories:
dogs,
cats
If the user only inputs: "I love dogs", the program will output the top 2 categories as "dogs, no other category found"
"no category" is the default response if there is only one category found or none at all.
I have created arrays lists for the following categories: dogs, cats, birds. These arraylists contain keywords that will trigger the program to recognize what category the user input will be in.
I basically need to get the highest likelihood and second highest likelihood (if applicable) and 'link' them to a string that will output what the category is.
This is my code, which attempts to take the top 2 highest likelihoods and get them to output on the console. my issue is getting the categories to link to their respective string to ensure the categories with highest likelihood are outputted.
//Create prioritization
int topDouble = 0;
String topString = "no category"; //default response
int secondDouble = 0;
String secondString = "no category"; // default response
ArrayList<Double> likelyDouble = new ArrayList<Double>();
likelyDouble.add(cats);
likelyDouble.add(dogs);
likelyDouble.add(birds);
ArrayList<String> likelyString = new ArrayList<String>();
likelyString.add("you talked about cats");
//to parallel likelyDouble cats category
likelyString.add("you talked about dogs");
//to parallel likelyDouble dogs category
likelyString.add("you talked about birds");
//to parallel likelyDouble cats category
int count = 0;
for (double d : likelyDouble){
if((d>0) && (d > topDouble)){
topDouble = (int) d;
topString = likelyString.get(count);
}
else if((d>0) && (d > secondDouble)){
secondDouble = (int) d;
secondString = likelyString.get(count);
}
}
System.out.print(topString + "\n");
System.out.print(secondString);
The output I get defaults to:
User input:
I like dogs and cats.
Dogs
no category
FYI The program determines what the likelihood that the user is talking about a certain category based on position in the sentence and number of times that category is referenced. The likelihood is a value that is calculated. so if the category is not mentioned at all, the likelihood is 0.
Thanks for all of your help!
I don't clearly understand what you are after, but I suspect it has something to do with your cast:
topDouble = (int) d;
You always set topDouble to 0 - assuming likelyhood is in the range [0,1].
Same goes to secondDouble.
Probably you wanted to declare topDouble and secondDouble as double, and remove the cast to an int - to get a double of the max/second value.
In addition - I cannot see you increase count, so you always get() the first element in the ArrayList.
Just a design thaught for a better approach [in my opinion]:
Create a new class: LikelyhoodStringDouble with 2 fields, one is a String and the other is a double. Make it implement Comparable [based on the double's value.
All you will have to do now is use Collections.sort() to sort the list, and get the top k elements you want [in your case k=2]
If I get you right, you can give a try to use a Map to store the likelyhood of your categories for every input any user can enter.
Sample given:
List<String> categories = new ArrayList<String>();
categories.add("dogs");
categories.add("cats");
categories.add("birds");
Map<String, Double> counterMap = new HashMap<String, Double>
for(String s : categories) {
counterMap.put(s, 0);
}
List<String> inputString = new ArrayList<String>();
inputString.add("you talked about cats");
inputString.add("you talked about dogs");
inputString.add("you talked about birds");
for(String s : inputString) {
for(String s2 : categories) {
//get the likelyhood of the category in the sentence
Double d = getLikelyhood(s2, s);
//add the likelyhood in your map
map.put(s2, map.get(s2) + d);
}
}
//after setting the likelyhood of the categories with the user input
//you just need to get the 2 major values in the map
//I'll let you a small algorithm for this
int x = 0;
String[] arrS = new String[m.size()];
for(Object o : m.keySet().toArray()) {
arrS[x++] = (String)o;
}
x = 0;
Double[] arrI = new Double[m.size()];
for(Object o : m.values().toArray()) {
arrI[x++] = (Double)o;
}
int max1, max2, posMax1, posMax2;
max1 = arrI[0];
max2 = arrI[0];
posMax1 = 0;
posMax2 = 0;
for(int i=1; i < arrI.length; i++) {
if (arrI[i] >= max1) {
max2 = max1;
max1 = arrI[i];
posMax2 = posMax1;
posMax1 = i;
} else if (arrI[i] > max2) {
max2 = arrI[i];
posMax2 = i;
}
}
System.out.println("Max category: " + arrS[posMax1]);
System.out.println("Second Max category: " + arrS[posMax2]);
Hope this helps you.