Adding Created Object to ArrayList During Initialization - Java - java

in Java, I am creating a class, and I would like to keep track of all objects the are created in this class. I have implemented a way to store the names of each object (using ArrayList), but I cannot figure out how to store the object itself in the ArrayList. Here is a snippet of my code:
static public class Ship {
private static ArrayList<String> ships = new ArrayList<String>();
private static ArrayList<Ship> shipObs = new ArrayList<Ship>();
String name;
private ArrayList<String> cruises = new ArrayList<String>();
int maxPassengers;
private static final String[] CABINS = new String[] {"Balcony", "Ocean View", "Suite", "Interior"};
private int[] passengers = new int[] {0,0,0,0};
boolean inService = false;
public Ship(String name, int maxPassengers) {
// Ensure that each ship has a unique name
if (ships.size() == 0) {
this.name = name;
ships.add(name);
}
else if (ships.size() >= 1) {
for (int i=0; i < ships.size(); i++) {
if (ships.get(i).equals(name)) {
System.out.println("Ship "+name+" cannot be created because that name already exists");
return;
}
}
this.name = name;
ships.add(name);
}
this.maxPassengers = maxPassengers;
As you can see, I have the static ArrayList that I would like to populate with all created ships. I assume that this population would take place in the initializing function, but the only method for doing so that I can see would to do something like
shipObs.add(this);
But that doesn't work...

As pointed out in the comments to the question, in addition to the problem asked about, there is another problem: That is, the premature return inside the constructor. Both problems can be addressed by calling the constructor indirectly, through a static method.
import java.util.ArrayList;
public final class Ship {
// private static ArrayList<String> ships = new ArrayList<String>();
private static ArrayList<Ship> shipObs = new ArrayList<Ship>();
String name;
private ArrayList<String> cruises = new ArrayList<String>();
int maxPassengers;
private static final String[] CABINS =
new String[]{"Balcony", "Ocean View", "Suite", "Interior"};
private int[] passengers = new int[]{0, 0, 0, 0};
boolean inService = false;
private Ship(String name, int maxPassengers) {
this.name = name;
// shipObs.add (this);
this.maxPassengers = maxPassengers;
}
public static Ship createAShip(String name, int maxPassengers) {
for (int i = 0; i < shipObs.size(); i++) {
if (shipObs.get(i).name.equals(name)) {
System.out.println("Ship " + name
+ " cannot be created because that name already exists");
return shipObs.get(i);
}
}
Ship theShip = new Ship(name, maxPassengers);
ShipObs.add (theShip);
return theShip;
}
}
I made the constructor private. This prevents client code (code that uses the class) from calling the constructor, forcing use of the static method. But, this disables inheritance. To make it clear that inheritance is not allowed, I added final to public class Ship.
As stated in the comments to the question, a constructor should not return before construction of the Object is complete. If a constructor discovers it cannot be completed, an Exception needs to be thrown.
The static method first checks for a duplicate Ship name. If found, it returns the Ship that bears that name. It would be a good idea to change that part of the code to throw an exception. A third option is to have it return null. Whatever the choice, it should be made clear to users of the class. This can be done using Javadoc.
If a duplicate name is not found, a new Ship is created and returned.
I also simplified the code that checks for a duplicate name. If shipObs.size() returns zero, the for loop is not executed. It is not necessary to guard by enclosing within an if.
I also removed ArrayList<String> ships. Since an Object in shipObs has a name field, ArrayList<String> ships is redundant.

You can't just use a return in the constructor, that would just avoid the next parameter association, you needs to throw an error to stop the instanciation process
If you may need the full objects in a list, track them only with a List<Ship>
You'll the simplified if/else system, you can try to iterate over an empty, it doesn't matter, so just do it
class Ship {
private static List<Ship> ships = new ArrayList<>();
String name;
int maxPassengers;
public Ship(String name, int maxPassengers) {
this.name = name;
for (Ship ship : ships) {
System.out.println(ship + " " + ship.equals(this));
if (ship.equals(this)) {
String msg = "Ship " + ship.name + " cannot be created because that name already exists";
System.out.println(msg);
throw new IllegalArgumentException(msg);
}
}
ships.add(this);
this.maxPassengers = maxPassengers;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Ship ship = (Ship) o;
return name.equals(ship.name);
}
}
If you don't care about the full objects, just use a List<String>
private static List<String> shipNames = new ArrayList<>();
public Ship(String name, int maxPassengers) {
for (String ship : shipNames) {
if (ship.equals(name)) {
String msg = "Ship " + name + " cannot be created because that name already exists";
System.out.println(msg);
throw new IllegalArgumentException(msg);
}
}
this.name = name;
shipNames.add(name);
this.maxPassengers = maxPassengers;
}
The following code will throw the exception at the second line
Ship a = new Ship("ship_1", 10);
Ship b = new Ship("ship_1", 10);
Ship c = new Ship("ship_2", 10);

Related

How to ensure two players or more inputted player names in an arraylist are not the same (java)

Hello in my monopoly game i need to make sure no inputted player names are the same to avoid confusion using an arraylist in java any way how to do it so only one player can have one name
public class Player {
private ArrayList<Property> properties = new ArrayList<Property>();
private final String name;
private int position;
private int money = 0;
public boolean inJail = false;
public int outOfJailCards = 0;
public int turnsInJail = 0;
public Player(String name){
this.name = name;
position = 0;
}
public String getName() {
return name;
}
// in monopoly.java
static ArrayList<Player> createPlayers(int numPlayers){
ArrayList<Player> players = new ArrayList<>();
for(int i = 1; i <= numPlayers; i++){
System.out.print("Player " + i + " name: ");
players.add(new Player(Input.read()));
}
return players;
}
}
import java.util.List;
import java.util.Scanner;
public class Input {
public static String read(){
Scanner scanner = new Scanner(System.in);
return scanner.nextLine();
}
Instead of directly adding the player to the array list, check with .contains() first. If not, ask for re-input. You will not be able to do this directly with a for loop, you will need to restructure your code.
PS: This sounds very much like homework in a programming course.
you can save the input from the user into a variable and check if the name already exists in the list:
String input = Input.read();
if(!list.stream().findAny(s -> s.getName().equals(input)).isPresent()({
players.add(new Player(input));
}
Stream API were used to check if name already exists in the list, but you could also use the .contains method, but first you need to override the equals method in your Player class.

How to add an object with multiple fields into an ArrayList?

I'm fairly new to Java and I've been trying to add an object to an ArrayList storing the respective object type. However, there is a catch. I want to have an indefinite amount of objects added into the ArrayList. The length is based on the user input, so I can't define them beforehand and use .add() after initializing the fields.
This is the class in question. There are 4 private fields and public getters and setters (only two included for context):
public class Player {
private int id; // This will be unique for each player.
private int roundScore; // Score accumulated during a round, suspect to be reset if the player rolls a double.
private int bankScore; // Secured score of a player.
private String name;
public Player() {
roundScore = 0;
bankScore = 0;
}
public void setID(int id) {
this.id = id;
}
public int getID() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
And this is the method I tried to use to generate players (this method is in another class):
public void generatePlayers(int num) {
Player dummyPlayer = new Player();
List<Player> playerList = new ArrayList<Player>();
Scanner sr = new Scanner(System.in);
for (int i = 0; i < num; i++) {
dummyPlayer.setID(i);
System.out.println("\nWhat is the name of player " + i++ + "?");
dummyPlayer.setName(sr.nextLine());
System.out.println(dummyPlayer.getName() + ", welcome to the game!");
playerList.add(dummyPlayer); // Oops, this is dumb.
}
}
The idea was to create an instance of a player object called "dummyPlayer", store the variables into the object and add the object into the ArrayList. "Should be fine, right?" or so I thought before I realized I basically added multiple instances of the same object which will all change if I change one of them because referencing is a thing.
Is there a way to individually set the fields of each value in the array? I'm sorry if I missed something vital or asking something stupid. I tried to search other questions but they didn't quite click. Thank you for your time.
As commented by #tgdavies, change generatePlayers() to move the new Player() line inside the for loop like so:
public void generatePlayers(int num) {
List<Player> playerList = new ArrayList<Player>();
Scanner sr = new Scanner(System.in);
for (int i = 0; i < num; i++) {
Player dummyPlayer = new Player();
dummyPlayer.setID(i);
System.out.println("\nWhat is the name of player " + i++ + "?");
dummyPlayer.setName(sr.nextLine());
System.out.println(dummyPlayer.getName() + ", welcome to the game!");
playerList.add(dummyPlayer); // Oops, this is dumb.
}
}
This way for every iteration of the for loop you create a new instance of Player, and you get to keep the as-is dummyPlayer variable (since local variables only exist within the block it is stated).
If for some reason there is a need to reference the dummyPlayer variable outside the for loop, you can state just the type and variable name before the loop and instantiate the Player class in the loop:
//... Same as above
Player dummyPlayer; //beware of null
for (int i = 0; i < num; i++) {
dummyPlayer = new Player(); //Player class instantiation
//... Same as above
}
dummyPlayer.toString(); //you can still reference dummyPlayer from here

Breakpoint errors in javaeclipse

Good evening everyone. I'm working on a piece of homework and I finally have it nearly complete. Currently, the only thing stopping compilation is a breakpoint error at line 42. Eclipse tells me that it is the variable "list" being uninitialized, however, i cant find where or why this is happening.
The program is for a homework assignment in beginning java. It is designed to import a list of names from a text file called names.txt, then be able to sort through them in an interface, and while the menu is yet to be added, I want to get compiled and make sure its working before I go changing things again.
import java.util.*;
import java.io.*;
public class Name {
private String givenName;
private int[] ranks = new int[11];
public static void main( String[] args ) {
List<Name> list = new ArrayList<Name>();
loadFile();
System.out.println( list.get( 0 ).getPop( 0 ) );
}
private static void loadFile() {
Scanner inputStream = null;
String fileName = "names.txt";
try {
inputStream = new Scanner( new File( fileName ) );
}
catch (FileNotFoundException e) {
System.out.println( "Error opening file named: " + fileName );
System.out.println( "Exiting..." );
}
while ( inputStream.hasNextLine() ) {
String line = inputStream.nextLine();
String[] tokens = new String[0];
String givenName = tokens[0];
int[] numList = new int[tokens.length - 1];
for ( int i = 1; i < tokens.length; i++ ) {
numList[i - 1] = Integer.parseInt( tokens[i].trim() );
}
list.add( new Name( givenName, numList ) );
}
}
// here we get the name for the
public Name(String name, int[] popularityRanks) {
givenName = name;
for ( int i = 0; i < 11; i++ ) {
ranks[i] = popularityRanks[i];
}
}
public String getName() {
return givenName;
}
public int getPop( int decade ) {
if ( decade >= 1 && decade <= 11 ) {
return ranks[decade];
}
else {
return -1;
}
}
public String getHistoLine( int decade ) {
String histoLine = ranks[decade] + ": ";
return histoLine;
}
public String getHistogram() {
String histogram = "";
for ( int i = 0; i < 11; i++ ) {
histogram += ranks[i] + ": " + this.getHistoLine( i ) + "\n";
}
return histogram;
}
}
In addition, I used lists to configure the variables, but now i am deeply regretting it as I feel far more comfortable with just multi-dimensional arrays. As this is homework related, I completely understand if no one wants to help me fix this second part and give me some code to change the lists to arrays.
I'm burnt out and just want it to compile at this point. Any pointers on where to go from here?
Your list declaration/initialization is in the main and you are trying to access it from loadFile method.
Just move you List<Name> list = new ArrayList<Name>(); as a class variable(put it right above the main) and your code should compile.
Eg:
public class Name {
private String givenName;
private int[] ranks = new int[11];
static List<Name> list = new ArrayList<Name>();
public static void main( String[] args ) {
loadFile();
......
Your list is not visible to the point your are going to add a Name object. Its better to pass the list as a reference to the loadFile() method, As like follows
loadFile(list); // Method call from the main().
And Load file
private static void loadFile(List list) {
// Your code
}
I've restructured your code fixing the scopes and the object definition. If your individual logic is correct(which I haven't really checked), you should get your desired output).
What you seem to have mixed up is the object and the calling client. The Name private class is a private object which is being instantiated in the main method. Subsequently the public methods of the Name object is being called upon.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Solution {
private static class Name{
private final int items = 11;
private String givenName;
private int[] ranks;
//Constructor
public Name(String name, int[] popularityRanks) {
givenName = name;
ranks = new int[items];
for (int i = 0; i < items; i++) {
ranks[i] = popularityRanks[i];
}
}
public String getName() {
return givenName;
}
public int getPop(int decade) {
if (decade >= 1 && decade <= items) {
return ranks[decade];
} else {
return -1;
}
}
public String getHistoLine(int decade) {
String histoLine = ranks[decade] + ": ";
return histoLine;
}
public String getHistogram() {
String histogram = "";
for (int i = 0; i < 11; i++) {
histogram += ranks[i] + ": " + this.getHistoLine(i) + "\n";
}
return histogram;
}
}
public static void main(String[] args) {
List<Name> list = loadFile();
System.out.println(list.get(0).getPop(0));
}
private static List<Name> loadFile() {
List<Name> list = new ArrayList<>();
Scanner inputStream = null;
String fileName = "names.txt";
try {
inputStream = new Scanner(new File(fileName));
} catch (FileNotFoundException e) {
System.out.println("Error opening file named: " + fileName);
System.out.println("Exiting...");
}
while (inputStream.hasNextLine()) {
String line = inputStream.nextLine();
String[] tokens = new String[0];
String givenName = tokens[0];
int[] numList = new int[tokens.length - 1];
for (int i = 1; i < tokens.length; i++) {
numList[i - 1] = Integer.parseInt(tokens[i].trim());
}
list.add(new Name(givenName, numList));
}
return list;
}
}
First of all, ill advise you declare your list outside main,
Second, you want to populate the list before calling getPop.
look where you have:
System.out.println(list.get(0).getPop(0));
At this point list.get(0) returns null since the list hasn't been populated yet...and from your code getPop(0) will return -1, so the line above basically doesn't mean anything at that point.
And as for converting the list to arrays to make it "multidimensional"....
First lists can also be "multidimensional", if u know how to declare them...e.g
List> list = new ArrayList();
is a 2d array list.
Second generic lists like the one above are way flexible and have huge advantages over arrays, for example they can be dynamically modified; you can change their size at runtime unlike arrays.
With that said, if you want to convert a list to an array you need the type of the list and it's size and then it's easy using the toArray() method...like this:
String[] array = list.toArray(new String[list.size()]);

Need help searching a linked list [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 8 years ago.
Hello everyone i have trouble searching a linked list. Basically I'm reading from a csv file and storing it in the linked list. I was able to add the list at the end. But when i search the list it keep saying it wasn't found. The method function is called contains. A method "contains" that takes a Country object as parameter and checks if the name of the country can be found in the list . to check whether object foo of type Country equals objects bar of type Country, you must override the "equals method" in class Country. When I'm running the code it returns not found and i found out the method contains from class countryNode returns null thats why its returns not found. I will appreciate the help thanks. Everything works except from the contains method. Below is my code:
public Country contains(Country obj)
{
if(this.isEmpty())
{
System.out.println("Sorry this is an Empty list");
return null;
}
else{
CountryNode current = first;
while(current!=null)
{
if(current.getCountry().equals(obj))
{
return current.getCountry();
// break;
}
current = current.getNext();
}
return null;
}
}
The class Country and the overrides method equals:
public class Country {
private String countryNames;
private SubscriptionYear[] subscriptions;
private int size;
private int location;
public Country(String country)
{
this.countryNames = country;
}
public Country(String country, int arraylength)
{
this.countryNames = country;
this.size = arraylength;
subscriptions = new SubscriptionYear[size];
location = 0;
}
public void addSubscriptionYear(int year, double subscription)
{
subscriptions[location]= new SubscriptionYear(year, subscription);
++location;
}
public String toString()
{
System.out.print(countryNames+"\t");
for(SubscriptionYear s: subscriptions)
{
//System.out.print(countryNames+"\t");
System.out.print(s.getSubscription()+"\t");
}
System.out.println();
return "";
}
public String getName()
{
return this.countryNames;
}
public boolean equals(Country obj)
{
return (this.countryNames==obj.countryNames);
}
}
This my test main file:
import java.util.Random;
import java.util.Scanner;
public class TestCountryList
{
/**
* Builds a list of countries to debug.
*/
private void debugListOfCountries(Country [] allCountries)
{
// TO COMPLETE
}
/**
* Builds a random list of countries.
*/
private void testRandomListOfCountries(Country [] allCountries)
{
Scanner keyboard = new Scanner(System.in);
System.out.println("How many countries do you want to add to the list?");
int requestedSize = keyboard.nextInt();
// Build the list out of a random selection of countries.
Random random = new Random();
CountryList selectedCountries = new CountryList();
for (int i = 0; i < requestedSize; i++)
{
int selectedIndex = random.nextInt(allCountries.length);
selectedCountries.add(allCountries[selectedIndex]);
}
// Note: To debug your list, comment this line in
System.out.println("List of countries: " + selectedCountries);
// Check if the name of a country is in the list.
// If the country is found, print the details.
// Otherwise output not found.
System.out.println("\nWhat country do you want to search for?");
String countryToFind = keyboard.next();
Country obj = new Country(countryToFind);
Country foundCountry = selectedCountries.contains(obj);
if (foundCountry != null)
{
System.out.println("Country " + countryToFind + " found with details:" + foundCountry);
}
else
System.out.println("Country " + countryToFind + " not found.");
}
/**
* Includes test examples for class GraphView.
*/
public static void main(String[] args)
{
// Create and set objects of type Country
//
final String FILENAME = "data/cellular.csv"; // Directory path for Mac OS X
//final String FILENAME = "data\cellular.csv"; // Directory path for Windows OS (i.e. Operating System)
final int NUM_COUNTRIES_TO_TEST = 3; // Note: Include test cases in addition to 3
// Parse the CSV data file
//
CSVReader parser = new CSVReader(FILENAME);
String [] countryNames = parser.getCountryNames();
int [] yearLabels = parser.getYearLabels();
double [][] parsedTable = parser.getParsedTable();
// Create and set objects of type Country
//
Country [] countries;
countries = new Country[NUM_COUNTRIES_TO_TEST];
Country current;
countries = new Country[countryNames.length];
for (int countryIndex = 0; countryIndex < countries.length; countryIndex++)
{
int numberOfYears = yearLabels.length; // OR numberOfYears = dataTable[countryIndex].length;
current = new Country(countryNames[countryIndex], numberOfYears);
for (int yearIndex = 0; yearIndex < numberOfYears; yearIndex++)
{
double [] allSubscriptions = parsedTable[countryIndex];
double countryData = allSubscriptions[yearIndex];
current.addSubscriptionYear(yearLabels[yearIndex], countryData);
}
countries[countryIndex] = current;
}
TestCountryList application = new TestCountryList();
// Note: Initially, to test your output you may hard code the number of
// countries added, and the array positions selected.
// However, make sure to comment this out before submitting your work.
//application.debugListOfCountries(countries);
application.testRandomListOfCountries(countries);
}
}
Try overriding equals method of Object as below:
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
return (this.countryNames.equals(((Country)obj).countryNames));
}
internally contains call countryList.equals method and equals method's signature is
public boolean equals(Object obj) {}
As opposed to
public boolean equals(Country obj) {}
Also you are just comparing two reference of strings while you need to compare the contents of String. So instead of
this.countryNames==obj.countryNames
You should say:
this.countryNames.equals(obj.countryNames);
you need to use equals or equalsIgnoreCase to compare String
public boolean equals(Country obj)
{
return this.countryNames.equals(obj.countryNames);
}

NullPointerException when calling a method from a dynamic object array

Good day,
Here is my code:
public class ArrayDirectory implements Directory {
private int allocatedSize = 0;
public Entry[] entryDirectory = new Entry[allocatedSize];
#Override
public void addEntry(Entry newEntry) {
newEntry = findFreeLocation();
entryDirectory = Arrays.copyOf(entryDirectory,
entryDirectory.length + 1);
}
private Entry findFreeLocation() {
Entry returnedEntry = new Entry();
for (int i = 0; i < entryDirectory.length; i++) {
if (entryDirectory[i] == null) {
break;
}
returnedEntry = entryDirectory[i];
}
return returnedEntry;
}
I've made the size of the entryDirectory dynamic; it increments each time the addEntry method is used. However, when I am trying to call a method of an entry object from the entryDirectory array, a NullPointerException is thrown.
public static void main(String[] args) {
ArrayDirectory d = new ArrayDirectory();
d.addEntry(new Entry("Jack", "Jones", 1234));
d.addEntry(new Entry("Brad", "Jones", 1234));
d.addEntry(new Entry("Olga", "Jones", 1234));
System.out.println(d.entryDirectory[0].getInitials());
}
Here is the getInitials() method of the Entry object.
public Entry(String surname, String initials, int extension){
this.surname = surname;
this.initials = initials;
this.extension = extension;
}
public String getInitials() {
return initials;
}
You never assign anything as element of your array entryDirectory, so NullPointerException arises when you try to invoke getInitials() on null-value object entryDirectory[0].
Remember that if you use Arrays.copyOf(),
for any indices that are valid in the copy but not the original, the
copy will contain null
See Arrays javadoc
In addition to Philip Voronov's answer, your findFreeLocation method is also implemented incorrectly. Assuming null means an absence of value, the proper implementation should be like this:
private int findFreeLocation() {
for (int i = 0; i < entryDirectory.length; i++) {
if (entryDirectory[i] == null) {
return i
}
}
return -1;
}
You can then use it like this:
public void addEntry(Entry newEntry) {
int loc = findFreeLocation();
if (loc >= 0) {
entryDirectory[loc] = newEntry;
} else {
entryDirectory = Arrays.copyOf(entryDirectory, entryDirectory.length + 1);
entryDirectory[entryDirectory.length - 1] = newEntry;
}
}
That said, I highly suggest you use a built-in collection, like ArrayList, to handle automatically resizing arrays. They are much easier to use, and their performance is also better (increasing the array size by one means you have to resize every time an item is added, in comparison to ArrayList's implementation, which doubles the size every time it fills up).

Categories

Resources