user cannot add key to hashmap in java while loop - java

I am training myself in the use of hashmaps and thought it would be a good idea to build myself a financial planner program. I am trying to prompt user for a string key (bill name) and then apply that to a double value (also input by the user) which equates to the value of the bill. The result will be a hashmap with bill names (such as internet or electricity, for eg) and the values that those bills come to.
I have built a class called InputData - as follows:
package financial.planner;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class InputData {
private double salary;
private Map<String, Double> bills;
private boolean chooseContinue;
public InputData(){
super();
this.salary = 0.0;
this.bills = new HashMap<>();
this.chooseContinue = false;
}
//getters and setters for salary
public double getSalary(){
return this.salary;
}
public void setSalary(double aSalary){
this.salary = aSalary;
}
//getters and setters for bills
public Map<String, Double> getBills(){
return this.bills;
}
public void setBills(Map<String, Double> aBills){
this.bills = aBills;
}
//getters and setters for chooseContinue
public boolean getChooseContinue(){
return this.chooseContinue;
}
public void setChooseContinue(boolean aChooseContinue){
this.chooseContinue = aChooseContinue;
}
public void FPSalary(){
Scanner scanVar = new Scanner(System.in);
System.out.print("Enter salary: \n");
this.setSalary(scanVar.nextDouble());
}
public void FPBills(){
Scanner scanVar = new Scanner(System.in);
Map<String, Double> billsMap = new HashMap<>();
while(!this.getChooseContinue())
{
System.out.println("Enter bill name: \n");
String billName = scanVar.nextLine();
System.out.println("Enter bill value: \n");
double billValue = scanVar.nextDouble();
billsMap.put(billName, billValue);
this.FPChooseContinue();
}
this.setBills(billsMap);
setChooseContinue(false);
}
public void FPChooseContinue(){
Scanner scanVar = new Scanner(System.in);
System.out.println("Any more to add (y or n)?\n");
String yesOrNo = scanVar.nextLine();
switch (yesOrNo) {
case "y":
break;
case "n":
this.setChooseContinue(true);
break;
default:
System.out.print("Please enter y or n");
}
}
}
And in my main:
package financial.planner;
public class FinancialPlanner
{
public static void main(String[] args)
{
InputData IDobject = new InputData();
System.out.println("Financial Planner 1.0");
IDobject.FPSalary();
IDobject.FPBills();
System.out.println(IDobject.getBills());
}
}
The Program runs according to plan unless I try to add a second key (ie bill name) - it ignores this request and runs straight to the bill value instead:
Financial Planner 1.0 Enter salary: 30000 Enter bill name:
gas Enter bill value:
450 Any more to add (y or n)?
y Enter bill name:
Enter bill value:
37 Any more to add (y or n)?
n {=37.0, gas=450.0}
I'd very much appreciate an experienced programmer to lend me a hand on this one - Im probably doing something pretty dumb - but I love programming and want to get better! please help! Any other advice about my code would be also greatly appreciated.

According to the docs, nextLine() does the following:
Advances this scanner past the current line and returns the input that
was skipped. This method returns the rest of the current line,
excluding any line separator at the end.
A stray newline character must be causing the String billName = scanVar.nextLine (); to skip a line, since it's theoretically a line to be read.
You can use next() instead, which reads until the next input delimiter.

Try this you have interchanged the yes and no blocks
public void FPChooseContinue(){
Scanner scanVar = new Scanner(System.in);
System.out.println("Any more to add (y or n)?\n");
String yesOrNo = scanVar.nextLine();
switch (yesOrNo) {
case "y":
this.setChooseContinue(true);
break;
case "n":
break;
default:
System.out.print("Please enter y or n");
}

The nextDouble() method leaves the '\n' symbol which gets picked up immediately by nextLine(), skipping over the next input thus throwing an exception. What you want to do is use nextLine() for everything, and parse it later. So just replace
double billValue = scanVar.nextDouble();
WITH
double billValue = Double.parseDouble(scanVar.nextLine());

Related

Input variable created at Main is a different value to that created in Method

I have created a method that gets input from the user. However, my issue is that when I attempt to return the value of the method, it continuously asks for a new number as input. Instead, I want it to ask for a number once, then return it.
For example: the following code illustrates what I want to achieve without a method, but including it within a method causes difficulties:
Working Code Inside Main:
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int age;
System.out.print("Enter Age: ");
age = input.nextInt();
System.out.print("/nYou're " + age + " years of age.");
}
However, when I try to do this within a method, I have difficulties:
Code Inside Method:
public static int getAge() {
Scanner input = new Scanner(System.in);
int number;
number = input.nextInt()
return number;
}
The issue is, whenever I try print System.out.print(getAge()); it asks for a number each time. Why does the first code allow me to print age without asking for a new number, but calling the method to print the number causes issues and continues to ask for a new number.
Effectively, I just want to call that method, ask for a number to input once, then call that method to return the number that the user has entered.
Its not just about having code to do job, but also about design. I would recommend below approach, features are:
A utility class and a generic method promptUserInput to prompt the user for input, passing your message
It will return a String object, convert it into other objects as required.
If you want to access it from other methods/classes, then store as instance variable, else simply use it to print or whatever is your plan.
You can handle the Scanner object to close it once everything is done, and parent thread is ready to die, for that you will need some change.
P.S.: My intention is not simply providing chunk of codes but make you think how to design. So, you may need to some change as per your requirement, scenarios and as you test.
Code:
public class UserTest {
public static void main(String[] args) {
User user = new User();
user.promptUserAge();
user.printUserAge(user.getUserAge());
//DO something.
user.printUserAge(user.getUserAge());
user.promptUserAge();
user.printUserAge(user.getUserAge());
}
}
public class User {
private int userAge = 0;
public void promptUserAge() {
String userInput = AppUtils.promptUserInput("Enter Age: ");
userAge = new Integer(userInput);
}
public int getUserAge(){
return userAge;
}
public void printUserAge(int age){
System.out.print("\nYou're " + age + " years of age.");
}
}
public class AppUtils {
public static String promptUserInput(String message) {
Scanner input = new Scanner(System.in);
System.out.println(message);
String userInput = input.next();
return userInput;
}
}
Your issue is that every time you call getAge() it is going to create a new scanner and try to get input again. Instead, when you return your number from getAge() the first time, save the value in a variable that you can reuse.
Something like this:
int age = getAge();
System.out.print("your age is " + age + " years of age");
You could store the user input in a class member variable, and reuse it later on.
import java.util.Scanner;
public class MyClass {
private int age = -1;
public static void main(String[] args) {
MyClass o = new MyClass();
o.getAge();
System.out.print("\nYou're " + o.getAge() + " years of age.");
}
public int getAge() {
if (age == -1) {
Scanner input = new Scanner(System.in);
System.out.print("Enter Age: ");
age = input.nextInt();
}
return age;
}
}

Program skipping one of the inputs

when my program gets to the part where it asks for the name of the fruit, it will output the string asking for the name, then immediately go to the next string output without waiting for the user input.
This seems to automatically assign a value of null to my name variable.
Fruit.java
public class Fruit {
String Name;
int Quantity;
double Mass;
public Fruit(String Name, int Quantity, double Mass) {
this.Name = Name;
this.Quantity = Quantity;
this.Mass = Mass;
}
public void Information() {
System.out.println("This fruit is an " + Name + ", there's " + Quantity
+ " of it and it weighs " + Mass + " grams");
}
}
Fruits.java
import java.util.Scanner;
public class Fruits {
public static void main(String[] args) {
Fruit menu[];
int number;
String name;
int quantity;
double mass;
System.out
.print("How many fruits would you like to add to the menu?: ");
Scanner input = new Scanner(System.in);
number = input.nextInt();
input.nextLine();
menu = new Fruit[number];
for (int i = 0; i < menu.length; i++) {
System.out.println("What would you like to name the fruit?: ");
name = input.nextLine();
System.out.println("How much fruits are there?: ");
quantity = input.nextInt();
System.out.println("What is the mass of the Fruit in grams?: ");
mass = input.nextDouble();
menu[i] = new Fruit(name, quantity, mass);
menu[i].Information();
}
input.close();
}
}
instead of input.nextInt(); use Integer.parseInt(input.nextLine()). it might solve your issue.
When you use input.nextInt() there is a %n char in hub. You need to use a input.nextLine() after to remove the line-break charcater. You can also use input.nextLine() for each variables and then parse it yourself.
Warning! In java convention the method name, attribute name and parameter name must begin by an lower case character.
the problem is scanning for ints, then nextLine. When you run .nexInt() I believe there is a newline character not scanned in, so this immediately messes with the following .nextLine(), as it only takes in the newline and nothing after
The easiest fix I am aware of is
number = input.nextInt();
input.nextLine();
menu = new Fruit[number];
And then the rest of the code should work
As an aside, usually you would start the loop from 0, because arrays start from 0, and you will have a blank first entry, but I don't think it matters in this particular piece of code

string whitespace throwing errors in a object array

i am trying to enter a book title "hoopa doopa"into my object array. when i try it throws a java.util.InputMismatchException.If i enter a string that has no spaces like"hoopa" the code will run fine all of the way through. What is causing this and how can I fix it? please help thanks
import java.io.*;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int counter = 0;
int numberOfProducts=0; //variable for when the user is asked to enter input the number of products to be entered
do { //this will validate the user input
System.out.println("How many products would you like to enter");
while (!input.hasNextInt()) {
System.out.println("That's not a number!");
input.next(); // this is important!
}
numberOfProducts = input.nextInt();
} while (numberOfProducts <= 0);
//end of the do while loop
Products[] products;
products = new Products[numberOfProducts+4];//create a array the size of the user input that was gathered
for (int i=0;i<numberOfProducts;i++)
{
products[i+4]= new Products(); // create each actual Person
System.out.println("What is the product #: ");
products[i+4].setItemNumber(input.nextInt());
System.out.println("What is the book name: ");
products[i+4].setNameOfProduct(input.next());
System.out.println("How many are in stock: ");
products[i+4].setUnitsInStock(input.nextInt());
System.out.println("What is the cost of the Item: ");
products[i+4].setPrice(input.nextDouble());
counter++;
}
products[0] = new Products(0001,"The Red Rose",1,29.99);
products[1] = new Products(0002,"The Bible",3,11.99);
products[2] = new Products(0003,"End of the Programm",2,29.99);
products[3] = new Products(0004,"WHAT!!! the....",1,129.99);
//____________________________________________________________4 products that are already made
for (int i=0;i<numberOfProducts+4;i++)
{
System.out.println(products[i].toString());
input.nextLine();
}
}
}
this is the other class
import java.text.NumberFormat;
public class Products
{
private int itemNumber;
private String nameOfProduct;
private int unitsInStock;
private double unitPrice;
public Products()
{
itemNumber = 0;
nameOfProduct = null;
unitsInStock = 0;
unitPrice = 0.0;
}
public Products(int num,String name,int inStock,double price)
{
itemNumber = num;
nameOfProduct = name;
unitsInStock = inStock;
unitPrice = price;
}
public int getItemNumber()
{
return itemNumber;
}
public void setItemNumber(int newValue)
{
itemNumber=newValue;
}
//----------------------------------------------
public String getNameOfProduct()
{
return nameOfProduct;
}
public void setNameOfProduct(String newValue)
{
nameOfProduct=newValue;
}
//----------------------------------------------
public int getUnitsInStock()
{
return unitsInStock;
}
public void setUnitsInStock(int newValue)
{
unitsInStock = newValue;
}
//-----------------------------------------------
public double getPrice()
{
return unitPrice;
}
public void setPrice(double newValue)
{
unitPrice = newValue;
}
//_______________________________________________
public double calculateTotalItemValue() //method that uses quantity on hand and price part3 1.A
{
return getUnitsInStock()* getPrice();
}//end of method
#Override
public String toString()
{
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
return"\nItem Number: "+getItemNumber() +
"\nItem Name: "+getNameOfProduct()+
"\nItem Quantity: " +getUnitsInStock()+
"\nItemPrice:" +currencyFormat.format(getPrice())
+"\nValue of Inventory: " +currencyFormat.format(this.calculateTotalItemValue());//part3 1.B
}
}
The Scanner sees the space in the book name as a delimiter since you are using the next() method. So when you go to read the nextInt() for the stock amount, the Scanner index is after the space in the book name String, and pulls in the remaining String data, which doesn't convert to an int. Instead, try something like this:
System.out.println("What is the book name: ");
input.nextLine();
products[i+4].setNameOfProduct(input.nextLine());
If you do not add the input.nextLine();, then it will appear as though the book name prompt gets skipped.
Scanner input = new Scanner(System.in);
Actually you are using scanner to get input and by default scanner delimiter is space. So you have to change the default delimiter of your code.
I think this is your problem:
products[i+4].setNameOfProduct(input.next());
What input.next() does is it reads the input from the user, until it reaches white space (the space between hoopa doopa). The function then passes hoopa to the setNameOfProduct method, and then passes doopa to the nextInt function, which gives a runtime error.
To fix your problem I would code
products[i+4].setNameOfProduct(input.nextLine());
Edit:
nextLine() function passes all characters up to the carriage return
Problem :
products[i+4].setNameOfProduct(input.next());
Solution 1 :
Just create another Scanner object for reading input with spaces
Scanner sc1=new Scanner(System.in);
products[i+4].setNameOfProduct(sc1.nextLine());
Solution 2 :
Or to use same scanner object
input.nextLine(); //Include this line before getting input string
products[i+4].setNameOfProduct(input.nextLine());

Output user data to display class

package developer;
import java.util.*;
import java.lang.Math.*;
public class Developer
{
static Scanner console = new Scanner(System.in);
String workType; // This will be either an app, or game
String name;
int pay;
int weekPay;
int hrsWorked;
double tax;
public Developer()
{
name = "Ciaran";
}
Developer(String appType, String coderName)
{
workType = appType;
name = coderName;
}// End developer
Developer(String appType, int pay) // Class to choose the pay rate depending on if it is a game or app
{
System.out.println("Are you coding an app or a game? ");
appType = console.next();
if(appType == "app")
{
pay = 20;
}
if(appType == "game")
{
pay = 30;
}
else
{
System.out.println("Please enter either 'app' or 'game' ");
}
}// End developer
Developer(int hrsWorked, double tax, int weekPay, int pay) // Class to choose the tax bracket which the developer is in
{
System.out.println("Please enter how many hours you have worked this week: ");
hrsWorked = console.nextInt();
weekPay = hrsWorked * pay;
if(weekPay >= 865)
{
tax = 0.4;
}
else
{
tax = 0.21;
}
}// End developer
Developer(int weekPay, int tax) // Gets the pay after tax
{
weekPay = weekPay * tax;
}// End developer
public void display()
{
System.out.println("This display method works");
System.out.println("User: " + name);
}
public static void main(String[] args)
{
Developer myDev = new Developer();
myDev.display();
} // End main
}// End public class developer
I am trying to get this program to ask the user what their name is; if they are developing a game or app and the amount of hours worked on it. With all this information I want to calculate how much the dev earns including tax. I cannot seem to get the display() method to ask the user the questions though and I have no idea what to do. I am hoping somebody out there can help me.
System.in will read input from the command line. You should wrap it with a java.util.Scanner and nextLine like this:
Scanner scanner = new Scanner(System.in);
String user_input = scanner.nextLine();
Be sure to check
scanner.hasNextLine()
before continuing or you'll get an error.
There are few things that could be done differently in your code, so let's break it down:
1.No need to make console static type, you can use:
private Scanner console = new Scanner(System.in);
2.weekPay is of type int, but your tax is double, if you don't want weekPay to be cast to integer, change it to:
double weekPay;
3.Later on, you are calculating weekPay after tax, so let's introduce a variable for that:
double weekPayAfterTax;
4.All these Developer() methods are constructors, and I think you are slightly confused here. Of course, you can have many constructors, but for us, let's keep only the no-params constructor:
public Developer() {
name = "Ciaran";
//you could initialise all the other variables here as well,
//I'll leave it as an exercise for you :)
}
5.Let's create a method that will ask all the questions and set respective variables:
void setData() {
//let's get the name
System.out.print("What's your name: ");
name = console.nextLine();
System.out.print("Are you coding an app or a game? ");
//since we want the user to enter 'app' or 'game'
//we need to loop until we got these
//we can do this by creating endless while loop,
//which we will end when we have correct input
while (true) {
workType = console.next();
if (workType.equals("app")) {
pay = 20.0;
//stop the loop
break;
}
else if (workType.equals("game")) {
pay = 30.0;
//stop the loop
break;
}
else {
System.out.print("Please enter either 'app' or 'game': ");
//back to top
}
}
//ok, we're out the loop, let's get number of hours
System.out.print("Please enter how many hours you have worked this week: ");
hrsWorked = console.nextInt();
//calculate weekPay
weekPay = hrsWorked * pay;
if(weekPay >= 865) {
tax = 0.4;
}
else {
tax = 0.21;
}
//calculate pay after tax
weekPayAfterTax = weekPay - weekPay * tax;
}
6.Let's update our display() method to show all the info:
public void display() {
System.out.println("This display method works");
System.out.println("User: " + name);
System.out.println("Work type: " + workType);
System.out.println("Pay: " + pay);
System.out.println("Week pay: " + weekPay);
System.out.println("Week pay after tax: " + weekPayAfterTax);
}
7.In your main method, you can finally create an instance of Developer class and get the data:
public static void main(String[] args) {
Developer myDev = new Developer();
myDev.setData();
myDev.display();
}
The code above can be improved (such as checking if user entered number where it's expected), and your problem can of course be done differently, but here's the start.
Please check out some tutorials to learn the basics, such as this one, or this one. Most of all, experiment and don't let others put you down for not understanding something.

Trouble with array outputs and prompting for user-input outputs

I have some trouble regarding my lab assignment:
When my program tries to prompt the user for input, the program outputs two questions on the same line and only takes the input for the second question.
The output of my program:
Please enter the name of the second employee:Please enter the number of the second employee:1
(They appear on the same line instead of separate lines)
Also the output for an array outputs like this:
0.00.00.00.00.00.00.00.00.00.0
instead of like this:
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
I'm not quite sure how to fix these two any help would be appreciated!
Here is my code:
Employee.java
//import java.util.*;
public class Employee
{
private String empName;
private int empNumber;
private String empAddress;
private double empSalary;
private double[] empBonus=new double[10];
public Employee(){}
public Employee(String empName_, int empNumber_, String empAddress_, double empSalary_, double[] empBonus_)
{
this.empName=empName_;
this.empNumber=empNumber_;
this.empAddress=empAddress_;
this.empSalary=empSalary_;
this.empBonus=empBonus_;
}
public String getName()
{
return this.empName;
}
public int getEmployeeNumber()
{
return this.empNumber;
}
public String getAddress()
{
return this.empAddress;
}
public double getSalary()
{
return this.empSalary;
}
public String changeAddress(String chAddress)
{
return empAddress=chAddress;
}
public double changeSalary(double chSalary)
{
return empSalary=chSalary;
}
public String addBonus(double[] empBonus)
{
String arrayBonus=new String("");
for(int i=0; i<empBonus.length;i++)
{
arrayBonus+=empBonus[i];
}
return arrayBonus;
}
public String toString()
{
return ("\nEmployee's name: "+empName+"\nEmployee's Number: "+empNumber+"\nEmployee's address: "+empAddress+
"\nEmployee's original salary: "+empSalary+ "\nEmployee's bonuses: "+addBonus(empBonus)+"\n");
}
}
EmployeeTester.java
import java.util.*;
public class EmployeeTester
{
public static void main(String[] args)
{
Scanner in1=new Scanner(System.in);
Scanner in2=new Scanner(System.in);
Scanner in3=new Scanner(System.in);
Employee emp1;
Employee emp2;
emp1=read_input("first", in1, in2, in3);
emp2=read_input("second", in1, in2, in3);
System.out.println(emp1.toString());
System.out.println(emp2.toString());
}
public static Employee read_input(String msg, Scanner scan1, Scanner scan2, Scanner scan3)
{
String name, address;
int num;
double salary;
double[] bonus=new double[10];
System.out.print("\nPlease enter the name of the "+msg+" employee:");
name=scan1.nextLine();
System.out.print("Please enter the number of the "+msg+" employee:");
num=scan2.nextInt();
System.out.print("Please enter the address of the "+msg+" employee:");
address=scan1.nextLine();
System.out.print("Please enter the salary of the "+msg+" employee:");
salary=scan3.nextDouble();
System.out.print("Please add a bonus for the "+msg+" employee:");
bonus[0]=scan3.nextDouble();
System.out.print("Add more bonuses to the "+msg+"employee? (y/n) \nNote: Enter 0.0 if you would like to terminate adding more bonuses: ");
if(scan1.next().startsWith("y"))
{
for(int i=1; i<bonus.length;i++)
{
System.out.print("Continue entering a bonus to "+msg+" employee:");
bonus[i]=scan3.nextDouble();
if(bonus[i]==0.0 || i==bonus.length)
{
break;
}
}
}
return new Employee(name, num, address, salary, bonus);
}
}
For your first problem just shift your Scanners inside your read_input method so they start fresh each time.
public static void main(String[] args) {
Employee emp1;
Employee emp2;
emp1 = read_input("first");
emp2 = read_input("second");
System.out.println(emp1.toString());
System.out.println(emp2.toString());
}
public static Employee read_input(String msg) {
Scanner scan1 = new Scanner(System.in);
Scanner scan2 = new Scanner(System.in);
Scanner scan3 = new Scanner(System.in);
...
For your second problem, in your addBonus method where you build the output string you are not adding any spaces or commas. Also it is a lot more efficient if you use a StringBuilder for this type of looped concatenation rather than repeatedly creating new string objects.
public String addBonus(double[] empBonus)
{
StringBuilder arrayBonus = new StringBuilder();
for(int i=0; i<empBonus.length;i++)
{
arrayBonus.append(empBonus[i] + ", ");
}
return arrayBonus.toString();
}
You do not need 3 different scanners, one will do.
For the printing part, you need println() or use '\n' for new lines.
E.g.:
System.out.println("Please enter the name of the "+msg+" employee:");
System.out.print("Please enter the name of the "+msg+" employee:\n");
In the first case, you are calling a function (println() instead of print()) that automatically appends a new-line to the outputes text. In the second case you are making the new-line part of the string (which you already used in the beginning of the first line printed)
The array output uses 0.0 because the values are floting point values (double in your case), which by default prints decimal parts. To only print the integer part, you will need to cast the value to an integer or use formatting for the double.
Casting:
double a = 0.0;
System.out.print("'a' as integer: " + ((int)a));
Formatting:
System.out.format("Here is a number: %.0f", a);
The number between the . and f specifies how many decimal places to output.

Categories

Resources