I am fairly new to object oriented programming, so I am still having some trouble grasping some of the basic concepts. So here I am trying to create a basic inventory program to keep track of stocks. Each stock contains couple details: company name, stock rating (AAA, AAa, Aaa, stuff like that), purchase price and numbers of shares. The program will ask user to input these details through command line prompt. And users can only input at most 12 stocks. If the user enters a stock twice, it will print out an error. And if the user has inputted one stock twice, it will also print out an error message.
Here is what I have done so far: Stock object
public class Stock {
private String companyName;
private String stockRating;
private int price;
private int numberOfShares;
public String getCompanyName() {
return companyName;
}
public int getStockRating() {
return stockRating;
}
public String getPrice() {
return price;
}
public int getNumberOfShares() {
return numberOfShares;
}
public Stock(String companyName, String stockRating, int price, int numberOfShares) {
super();
this.companyName = companyName;
this.stockRating = stockRating;
this.price = price;
this.numberOfShares = numberOfShares;
}
Now, I am trying to create stock inventory program
import java.util.*;
public class StockInvetory {
private static final int INVENTORY_SIZE = 12;
private Stock [] stocks;
public StockInvetory() {
stocks = new Stock [INVENTORY_SIZE];
}
private static void StockInventory() {
for (int i = 0; i<INVENTORY_SIZE; i++){
Scanner console = new Scanner(System.in);
System.out.println ("Stock's name:");
String stockName = console.next();
System.out.println ("Stock's rating");
String stockRating= console.next();
System.out.println ("Stock's price:");
int stockPrice = console.nextInt();
System.out.println ("Numbers of shares: ");
int numberShares= console.nextInt();
stocks [i]= new Stock(stockName, stockRatings, stockPrice, numberShares);
}
public static void main (String [] args){
StockInventory();
}
}
So my questions are the following:
The first stock object program should be okay, my problem is the stock inventory program.
With this code, private Stock [] stocks, does it mean that the stock inventory program will store the info into an array? If it is, how do I store all the details associated with a particular stock, company name, price, etcs together. Do I have to create a multi-dimensional array in order of keep track of all the details? Like one row contains all the details about one stock, and second row contains details about another stock. And to determine if the user has entered one stock twice, do I use "equalsIgnoreCase" to do the comparison? I know I probably need to create another method for the stock Inventory.
Thank you very much in advance for your assistance.
Once you read in the name, rating, price, and share count, you need to call the constructor on your class Stock to create an instance of the class and assign it to the next item in your stocks[] array.
Like so:
stocks[0] = new Stock( stockName, stockRating, stockPrice, numberShares);
Then you'll need to put the lines of code that you're using to read from the console, plus my line that creates the new Stock object into a loop so that you can read in all 12 stocks:
for( int i = 0; i < INVENTORY_SIZE; i++ )
{
System.out.println ("Stock's name:");
String stockName = console.next();
System.out.println ("Stock's rating");
String stockRating= console.next();
System.out.println ("Stock's price:");
int stockPrice = console.nextInt();
System.out.println ("Numbers of shares: ");
int numberShares= console.nextInt();
stocks[i] = new Stock( stockName, stockRating, stockPrice, numberShares);
}
Now, this isn't perfect, since it will require users to always enter a full set of 12 stocks, so you'll need to figure out how to let the user abort out of the loop if they're done, and you'll still have to add that error checking you want, to ensure that no duplicates are entered, but it should initialize your individual objects and assign eachh one to the array elements.
private Stock [] stocks, does it mean that the stock inventory program
will store the info into an array? If it is, how do I store all the
details associated with a particular stock, company name, price, etcs
together.
Your array is like a list of stocks. But just because its one object, doesn't mean it only contains one piece of data. It can hold Strings, ints, and other user-defined data types. Therefore, you can store pieces of data relating to the stock inside the Stock object.
public class Stock {
private String companyName;
private String stockRating;
private int price;
private int numberOfShares;
Those are all stored in each Stock object, and can be accessed by the getter methods you defined.
int stockdata = stocks[4].getPrice();
However, to initialize your Stock array, you want to create a new Stock object for each area, like so:
for(int i = 0; i < INVENTORY_SIZE; i++) {
stocks[i] = new Stock(foo, bar, lorem, ipsum);
}
The variables used here are just placeholders, so you can create your parameters by reading from the console like you're doing above.
These design principles for OOP should help you understand the relationship between data and containers.
For the second part of your question, you can look at just comparing one of the data values, like companyName, or implementing an interface like Comparable.
for(Stock s : stocks) {
if(stockName.equals(s.getCompanyName()) {
// ERROR!
}
}
You may want to provide some way to break the loop in certain condition if user does not want to input all 12 information. However, it is totally on your requirements.
In that case, you may have to use other options like List or vector.
Each object can have multiple variables , like in your case rating, price ,name and share which are bound to each object. So when you store an object in an index of array, you are actually storing all those information contained by that object in one single place. So in this case, you do not have to create multidimensional array.
You can override your equals method based on what defines the object as equal and use it to determine if same stock is provided again. This will return true if both object are same, otherwise false.
You can post your updated code and log here so that you can get suggestion regarding your exception
In a real world scenario some questions come to mind:
price shouldn't be an integer because a price is usually an amount in a specific currency. Check this money related question.
Stock rating would be better represented using an Enum. See doc
Related
I am relatively new to Java and would like to know how to store variables separately from a single line of user input.
At the minute the user is prompted to enter football results in the following format
home_name : away_name : home_score : away_score
and I am using a while loop to continue to ask user for input until they enter "stop"
(while (input != "stop))
Once the loop is broken I would like my program to output a variety of data such as total games played, but I'm struggling to store the home_name, away_name etc.. especially if the user wishes to enter multiple lines of results.
Two mainstream ways to store a "record" are:
Maps
Data objects
A map is more generic:
Map<String,String> match = new HashMap<>();
match.put("home_name", "Alvechurch Villa");
match.put("away_name", "Leamington");
match.put("home_score", "0");
match.put("away_score", "6");
You can add a map to a list:
List<Map<String,String>> matches = new ArrayList<>();
matches.add(list);
... and retrieve them:
Map<String,String> match = matches.get(0);
System.out.println(match.get("away_score"));
A data object is more tuned to your data format, but you have to write the class yourself.
public class Match {
public String homeName;
public String awayName;
public int homeScore;
public int awayScore;
}
Now you can use this class:
Match match = new Match();
match.homeName = "Studley";
// etc.
You can add and retrieve these from lists too:
List<Match> matches = new ArrayList<>();
matches.add(match);
Match aMatch = matches.get(0);
This is simple, but it's considered bad practice to have public fields like this - it's better to get at them via methods. For brevity, here's a data class with only one field:
public class Player {
private String name;
public Player(String name) {
this.name = name;
}
public String name() {
return name;
}
}
Player neilStacey = new Player("Neil Stacey");
You can use the same technique with all the fields in Match.
(A common style is to name a method like this getName(), and also to have a setName(). I have used a different style and made the object immutable, in an effort to set a good example!)
One advantage of the data object is that it has different types for different fields: homeName is a String, homeScore is an integer. All the fields in the Map are Strings. You can get around this by using Map<String,Object> but then as a consumer you have to cast to the right type when you read.
String homeName = (String) match.get("home_name");
Data objects allow the compiler to do a lot of compile-time checking that helps you know your code is correct. If you use a map, you won't find out until runtime.
Prompt the user separately for each input.
System.out.println("home_name: ");
String hN = scan.next();
System.out.println("away_name: ");
String aN = scan.next();
System.out.println("home_score: ");
String hS = scan.next();
System.out.println("away_score: ");
String aS = scan.next();
I am taking a Java class right now and we are supposed to be making a text based game. One of the options in our game is to allow the person to choose between 3 ship types; small, medium, and large. Based on their selection, they will be able to choose how many people travel on the ship. Small allows up to 3, medium up to 6, and large up to 9. Once they have made this selection, they are allowed to enter a name for each crew member and select a research specialization. Previously, we had set these as separate menus (select Ship, crew size, research spec, and names) but I'm beginning to think it would be easier to select crew size, names, and research spec in the same menu.
That said, we are working on arrays/ArrayLists right now and we're supposed to use an array to list the characters (NPCs) in the game. So, I need to figure out how to create an array based on how many crew members are chosen (between 1 and 9), have it then prompt for a name, and then allow them to choose from a list of research specs. They will enter a single letter for their choice but the array should put the full name of the research spec in it. I found some code in another post I think might be helpful in this situation but it's barely scratching the surface I think. Any help would be greatly appreciated.
public class Name {
public static void main(String[] args) {
ArrayList<String> name = new ArrayList<String>();
ArrayList<(how do I tell it to select a character option here?)> researchSpec = new ArrayList<(selected option)>();
Scanner sc = new Scanner(System.in);
while (true) {
System.err.println("Please enter the name of your crew member: ");
name.add(sc.next());
System.out.println("Please select a Science Specialization for your crew member");
researchSpec.add(sc.next());
}
}
}
When you have a small, predefined set of possible values for something, an enum is often ideal for representing those.
public enum Specialization {
PHYSICS,
CHEMISTRY,
BIOLOGY
}
Now, you can define variables of the type Specialization and lists of the type List<Specialization>, and refer to the values as Specialization.PHYSICS etc. This is better than using a String because you're not running the risk of e.g. misspelling a specialization somewhere in the code, such as adding "Pysics" to the list in one place and wondering why the if (specialization.equals("Physics")) never works.
However, you still need to have some ifs, a switch, or a Map for the mapping from letters to specializations - unless you get fancy with the enums. An enum is actually a class, but you can't use new on it - instead, there's automatically one instance per identifier (in this case, PHYSICS, CHEMISTRY, and BIOLOGY are the three only instances). You can add fields, constructors, and methods to an enum class, so that you can endow each value with different properties:
public enum Specialization {
PHYSICS('p', "Physics"),
CHEMISTRY('c', "Chemistry"),
BIOLOGY('b', "Biology");
private char menuLetter;
private String displayName;
private Specialization(char menuLetter, String displayName) {
this.menuLetter = menuLetter;
this.displayName = displayName;
}
public char getMenuLetter() { return menuLetter; }
public String getDisplayName() { return displayName; }
}
You can use values() to get a list of all of the values. For example, this will generate the menu options (I'll leave the selection as an exercise for you):
for (Specialization s : Specialization.values()) {
System.out.println(s.getMenuLetter() + ": " + s.getDisplayName());
}
Edit: Or with a regular loop:
Specialization[] specializations = Specializations.values();
for (int i = 0; i < specializations.length; i++) {
System.out.println(specializations[i].getMenuLetter() + ": " + specializations[i].getDisplayName());
}
Creating an Array based on the selection and then filling it would look like this:
NPC[] npcs;
if (amount > maximum) {// both values prompted
System.our.println("Too much crew members.");
return;
}
npcs = new NPC[amount];
for (int i = 0; i < npcs.length; i++) {
String name = // prompt name
Specialization s = // prompt that somehow -> enum solution by Aasmund Eldhuset
npcs[i] = new NPC(name, s);
}
The NPC class would look like this:
public class NPC {
public (final?) String name;
public (final?) Specialization spc;
public NPC(String name, Specialization s) {
this.name = name;
this.spc = s;
}
}
I am pretty new to coding. This is my first class and it's an intro to Java. I am stuck on one part of the assignment - not sure where to go.
I have an inventory program that has a Product class and a Stock class. The stock class needs to be able to use the product object in an array in methods to 1)tell if a product is in stock w. its sku. 2) return quantity with sku 3)add or remove product from Stock.
It sounds simple enough but I'm not understanding it. I've been searching the internet and reading my book for weeks to no avail so I thought I'd give this a try.
My product class contains the usual get/set methods for qty, sku, price, name
This is my Stock class:
public class Stock
{
private static final int MAX = 100;
int currentNoOfProd = 0;
Product[] productsArray = new Product[MAX];
//I need an empty stock array constructor
/* public Stock (int[] stockArray)
{
this.productsArray = stockArray;
}*/
//method to tell if Product is in Stock with SKU
public void inStock()
{
for(int i = 0; i< MAX; i++)
{
System.out.println("testing stock inventory\n" + productsArray[i].getSKU());
if (productsArray[i].getQty() > 0)
{
System.out.println("In Stock");
}
}
}
//return the quantity of a Product given its SKU
public void qtyInStock()
{
for(int i=0; i< MAX; i++)
{
System.out.println("in qtyInStock loop\n" + productsArray[i].getSKU());
System.out.println("getting quantity qtyInStock" + productsArray[i].getQty());
}
}
//add or remove a Product from Stock
}
My stock class is just me testing ideas to try and do /something/ but at this point I'm completely lost. This may be vague but I don't know how much more specific I can get.
I am hard coding the sku, name, price, and quatity in my driver program, if that helps, when I initiate a product object.
Suggestions would be wonderful or tips, anything really to help me move along and figure this out and learn. Thanks so much.
Some pointers that hopefully guide you forward:
1. Instance variables in the Stock class
By default, you should always use the "least visible" scope, i.e. private, in your instance variables. This means that Product[] productsArray should be replaced with private Product[] productsArray. Variables in the private scope can only be accessed by the containing class, which is a good thing when the class is a part of a larger application and you are debugging things.
2. Method telling whether a product is in stock or not
Your inStock() method is currently neither using a "SKU" (Stock keeping unit) for input nor returning anything back to the caller. It would seem better to change the method signature to
public boolean inStock(String sku)
instead. The iteration over productsArray looks ok, even though you can make it even more concise using the for-each construct, which has been available from Java 5 onwards (the array knows its size after it has been created):
for (Product p : productsArray) {
// you can use p.getQty() and p.getSKU() within the loop
...
}
Please note that because your array can/will contain null elements, you should check for p != null before invoking any methods on p. Basically you just need to return true from the loop when you find a match with a positive quantity and the given "SKU". Otherwise return false at the end of the method because no matches were found.
3. Return quantity of a product
The method signature should be changed to
public int qtyInStock(String sku)
If we assume that productsArray only holds one Product for a given "SKU", then you can simply iterate over the array and return the quantity of a product if one is found.
4. Add or remove product from Stock.
You probably want to split this requirement into two different methods: one for adding and one for removing stuff from your stock. For example:
public void addProduct(Product p)
and
public void removeProduct(Product p)
These are more difficult methods to implement, because they require manipulating the underlying productsArray. Also, in a real life application, the method would possibly throw an Exception if something unexpected happens (stock out of space, product not in stock etc.).
If we assume that your MAX array size is large enough, and that you only store one Product per "SKU" in the array, then basically you need to:
When adding a product: Iterate over the array and try to find a product with a "SKU" matching the input product's "SKU". If a match is found, increment the quantity based on the quantity of the input product; else store the product in the first available slot (having productsArray[i] == null) in the array.
When removing a product: if a match is found in the array, just set it to null using productsArray[i] = null.
Note that in these array-modifying methods, it is more practical to iterate using the for loop that keeps track of the index (for (int i = 0; i < MAX; i++)), which you already used in your example code.
You should use a Collection, e. g. ArrayList<Product> instead of Product[]. Your stock would not have fixed size and you will get some useful API as for example list.add(product), list.contains(product) etc.
I am attempting to create a list of bank records. Each record consists of a first name, last name, phone number, and balance. In the first class I ask the user for this information, then create a new instance of the records class to add to the list. However, as I add more records it replaces all records with the most recent one, which you can see with my showAllRecords() method. How do I fix this?
The add and showAllRecords method in the main class. These methods are called from a switch statement in the main method:
private static void showAllRecords()
{
if(records.bankRecords.size() == 0)
System.out.println("There are no records.");
else
for (int i = 0; i < records.bankRecords.size(); i++)
{
System.out.println(records.bankRecords.get(i));
}
}
private static void add()
{
Scanner scan = new Scanner(System.in);
System.out.print("Please enter the first name: ");
String firstName = scan.next();
System.out.print("Please enter the last name: ");
String lastName = scan.next();
System.out.print("Please enter the phone number: ");
String phoneNumber = scan.next();
System.out.print("Please enter the balance: ");
int balance = scan.nextInt();
bankRecords.add(new records(firstName, lastName, phoneNumber, balance));
}
The records class
public class records
{
public static String firstName;
public static String lastName;
public static String phoneNumber;
public static int balance;
LinkedList<records> bankRecords = new LinkedList<records>();
public records(String tFirstName, String tLastName, String tPhoneNumber, int tBalance)
{
firstName = tFirstName;
lastName = tLastName;
phoneNumber = tPhoneNumber;
balance = tBalance;
}
}
The problem occurs because all the fields in records class are static. Remove the static keyword from the declarations of fields. As they are static whenever you create a new object of records class you overwrite those static fields.
Static fields belong to the class not to the object.
Remove the LinkedList instance that you have declared in records class. Why are u doing that. Declare it in your main class and try to use ArrayList which I think is better in your case. The reason is that records has static fields
Why your class name starts with small letter. Its a very very bad practice.
You have an inherent planning problem.
There is a difference between the entity "Bank Record", which includes, as you said, a name, balance etc., and the entity "List of Bank Records", which includes, well, a variable number of bank records.
Your "records" class (please use a capital letter in the beginning of a class name) tries to mix both. So you have both a record and a list inside it. You should separate the two entities. You then create a new "Record", and add it to the "ListOfBankRecords" objects.
Also, it seems that you have both a variable and a variable called "records". This is also why a capital letter would have been good. You shouldn't have a variable that has the same name as a class.
I got a String[] which contains of multiple user details. Something like this:
Wilson#$20#$Male=#=Raymond#$25#$Male=#=Sophie#$20#$Female
I wanted to split the string up and organize it into multiple array. Such as one array for Name, one array for Age and another array for Gender. Up to this point I managed to split the String[] into something like this.
String[] User = student.split("=#=");
User[0] = Wilson#$20#$Male
User[1] = Raymond#$25#$Male
User[2] = Sophie#$20#$Female
I don't really know how to organize it from this point. Any comments and answers are highly appreciated!
EDIT
Wilson#$20#$Male=#=Raymond#$25#$Male=#=Sophie#$20#$Female
The above part is actually a value that is returned from the server and I wanted to handle this value. Thank you for all the replies. I think I understand a bit in theory wise, but I'm having slightly issue in implementing codes.
I agree with the suggestions of creating a class for each user - it's the Object Oriented way. So I included it in the example below. But you could probably change it easy enough if you want to do arrays or some other structure.
However, what I want to add is a way to use the Java classes java.util.regex.Pattern and java.util.regex.Matcher to extract both records AND fields in one go from your input string. (I haven't programmed for Android, I assume they are available though.)
The general plan for the pattern is: (record delimiter or nothing)(field1)(delim)(field2)(delim)(lastfield)(record delimiter + rest of input)
The algorithm basically loops through the input with the above pattern. The pattern extracts various groups for the fields (depending on how your record's format) and then also a last group that contains the remainder of the input string. This remainder is used as the new input string for the next loop. So each iteration of the loop does one record.
Here is more complete example code which you can run. You might need to study up on regular expressions to understand the pattern, which is the important part of the algorithm. You can start with the Javadoc for the java.util.regex.Pattern class.
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestPatternMatch {
public static void main(String[] args) {
List<User> result = new ArrayList<>();
String input =
"Wilson#$20#$Male=#=Raymond#$25#$Male=#=Sophie#$30#$Female";
Pattern recPatt =
Pattern.compile("^(=#=|.{0})(.+?)#\\$(\\d+)#\\$(.+?)(?==#=)(.*$)");
// ^match start of line
// ^match record delimiter or nothing
// ^match name field (reluctant)
// ^match field delim
// ^match age field
// ^match field delim
// match gender field^
// zero-width (non recording) lookahead for record delimiter^
// match rest of line until end^
Matcher recMatcher;
String workStr = input; // start with whole input
while (workStr != null && workStr.length() > 0) {
recMatcher = recPatt.matcher(workStr);
if (recMatcher.matches() && recMatcher.groupCount() >= 5) {
result.add(
new User(
recMatcher.group(2), //name
Integer.parseInt(recMatcher.group(3)), //age
recMatcher.group(4) //gender
)
);
workStr = recMatcher.group(5); // use tail for next iteration
} else {
workStr = null;
}
}
System.out.println(result); //show result list contents
}
}
class User {
String name;
int age;
String gender;
/** All argument constructor */
public User(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
/** Show contents of object fields */
public String toString() {
return "User ["+ name + ", " + age + ", " + gender + "]";
}
}
The basic pattern structure can be reused for many different record formats.
Create a User object to store all fields (name, age, gender) and create a list to hold all data.
Your best bet here, is to use an object to hold these values. Objects are the standardized way to hold values that relate to one another, in one Object. ie:
public class Person
{
private String name;
private int age;
private String gender;
// Gender could be a boolean value really, but you've stored it as a String.
}
In the constructor you would request each value and assign it to these fields. It would look something like:
public Person(String name, int age, String gender)
{
this.name = name;
// etc etc
}
That way you have one array, with no need to do any tokenizing of Strings to get to individual values :). You will also need to implement some Accessors and Mutators to get at the values within the Object.
Why not create a User class and maintain a list of User instances.
class User {
String name;
String gender;
int age;
}
The best solution would be to create an class User. If you want to avoid it, try:
String[] User = student.split("=#=");
String [][] details=new String[user.length][3];
String [] temp=new String[3];
for(int i=0;i<User.length;i++){
temp=User.split("//");
for(j=0;j<3;j++){
details[i][j]=temp[j];
}
}