Java football team map that references List of Team objects - java

I'm new to Java and currently stuck on an assignment question.
I need to create a method for the LeagueAdmin class called addTeam(), which takes two arguments and returns no value. I'm given the header: public void addTeam(String division, Team team)
The method should check to see if a list for that division already exists in the teams map.
If the list exists, then the new Team should be added to the existing list of teams for that division.
If the list does not exist, then a new empty list of Team should be created and the new Team should be added to it, then a new key-value pair should be created in teams with division as the key and the new list as the value.
My code so far is as follows:
import java.util.*;
public class LeagueAdmin
{
public Map<String, List<Team>> teams;
/**
* Constructor for objects of class LeagueAdmin
*/
public LeagueAdmin()
{
this.teams = new HashMap<String, List<Team>>();
}
}
I have separate class as follows:
public class Team
{
private String name;
private String division;
private int won;
private int drew;
private int lost;
// no need to record points as = 3*won + drew
/**
* Constructor for objects of class Team
*/
public Team(String aName, String aDivision)
{
name = aName;
division = aDivision;
// no need to set won, drew and lost to 0
}
}
If anyone can give me some pointers that would be great,
Thanks, Kat

Before answering your question, a couple of suggestions.
always declare local variables and fields as final when possible
always format your code. Seems superfluous but it's something I don't see done often
initialize final fields in-line, not inside the constructor, if possible
don't expose fields, which are part of implementation details
Edit: being that maybe you need a simplified version, I'll also add that, but keep reading all my answer, it's fun!
Follow the comments inside the code to understand the flow.
public class LeagueAdmin {
private final Map<String, List<Team>> teams = new HashMap<String, List<Team>>();
public void addTeam(final String division, final Team team) {
// We retrieve the team list, if any
List<Team> list = map.get(division);
// We check if the list was already there, or we have to create a new one
if (list == null) {
// The list is null, we need to insert a new one!
list = new ArrayList<>();
map.put(division, list);
}
// We add the team to the list
list.add(team);
}
}
Now, for a more "new" and simplified version, which does the exact same thing as the one above, the implementation would be
public class LeagueAdmin {
private final Map<String, List<Team>> teams = new HashMap<String, List<Team>>();
public void addTeam(final String division, final Team team) {
teams.computeIfAbsent(division, __ -> new ArrayList<>()).add(team);
}
}
Since Java 8, the Map interface exposes a new method
computeIfAbsent(Key, Function)
What this does is
try to get the value associated with the inputted key
if no value found, use the Function argument to associate a new one
return the associated value
Also, you'll ask yourself what __ -> is.
Well, __ is just a valid variable name, used to say "hey, I don't need that"
The -> (arrow) is part of a lambda expression, which is basically an in-line function

The Answer by LppEdd suggesting computeIfAbsent is correct, but perhaps not what your course instructor is looking for. She/he probably wants you to more coding than that, as we did do in real work before that new method was added recently.
The old-fashioned of the addTeam(String division, Team team) method you need to add to LeagueAdmin would ask the map if it has a key for the division string. If no such key, add one, and put as its value a new empty List of teams to which you have added the team in question. If there is such a key, retrieve its value, a List, and then add the team in question to that list.
As a homework assignment, to do the learning you need to struggle with this a bit rather than copy some existing code. Study the JavaDoc for the Map and List interfaces. Follow my prose above as pseudo-code to walk you through the logic. Be sure you understand the ideas behind each class, especially the key-value pairing of a map (also known as a dictionary or an associative array). Draw a diagram on paper, imagining each step I outlined above.
So a league object holds a Map object. The map holds a collection of keys, each key being a division name (a String in your situation, more likely a Division class in real work). Being a key in a map means each division name will lead you to a List object, a collection of teams. A List keeps items in the order in which they are added. A Set would like work just as well here, by the way.
Note in this diagram how one of the List objects is empty, meaning it has not yet had any teams assigned. An empty list is not nothing; an empty list is something. The empty list is still a valid object, just like a fruit basket without any fruit in it is still a basket. If no list, empty or otherwise, has yet to be assigned to a key in a map, the key points to null where null really does mean “nothing at all”. We see in this diagram that the “division-z” key in the map has not yet been assigned any List object at all, so it points to nothing, null.

Related

How to construct a user(/input)-specified number of objects

I'm currently doing an intro level undergrad CS course (learning basics of 'program'&'class' building using Java).
The relevant part of my personal (&job related) project: I have a list of zip codes associated with One county.
I'm gonna define a class called 'County'. Then I'm gonna use this class to construct an object of type County, called 'middlesex'.
ie: County middlesex = new County();
Now, in this object, I want to construct a number of objects of class-type ZipCode.
ie: ZipCode objName = new ZipCode();
(Each such ZipCode object is gonna contain certain instance data).
My problem is this. Assume that I don't know how many zipcodes are contained in the Middlesex county. However, I have a .txt file that contains just a list of all the zipcodes of Middlesex county.
Let's say there are n number of zipcodes in this list.
In the object 'middlesex', of class-type 'County', I want to set up a loop. This loop will scan each zipcode in the list, then construct an object of class-type ZipCode for each zipcode.
Thus the loop may go thru n iterations, and construct n objects of type ZipCode.
Thus, for every iteration of the loop, a unique object-reference-name must be created (corresponding to the particular zipcode in the list).
Part of this problem (but distinct and optional), is that I want to know how (if possible), I can set up a structure that allows an inputted (scanned) string to be used as the name of an object-reference.
I apologize if I've made incorrect terminology use. I know that many are gonna suggest arrays. I haven't learned about them yet, but I gotta read about them over this weekend for school. I'm just gonna try to figure this out for a day or two, and then just move on to using arrays to perform this task.
So, if I've made any sense to anyone, is what I'm trying to do possible without arrays?
Thank u.
You're describing a very basic scenario, one where one object contains (possibly) many references to objects of a 2nd type, what we call a constructor called "composition" where the relationship here is a "has-a" relationship, County has-a (or has-many) zip codes
As opposed to using inheritance to wrongly try to solve this, the "inheritance" relationship or the "is-a" relationship -- County is not a zip code and zip code is not a county.
The code to create this can be very simple, something like:
import java.util.ArrayList;
import java.util.List;
public class County {
private String name;
private List<String> zipCodes = new ArrayList<>();
// constructor that takes county name
public County(String name) {
this.name = name;
}
public void addZipCode(String code) {
zipCodes.add(code);
}
// ..... more code
If a zip code is a single String, then no need to create a new class for this. If however it is more complex and holds more data than a single String, then create a class for ZipCode, and change the code above to something like
import java.util.ArrayList;
import java.util.List;
public class County {
private String name;
private List<ZipCode> zipCodes = new ArrayList<>();
// constructor that takes county name
public County(String name) {
this.name = name;
}
public void addZipCode(ZipCode code) {
zipCodes.add(code);
}
// getters, setters, a decent toString method override...
Where ZipCode could contain....
public class ZipCode {
String code;
// other fields if needed....
public ZipCode(String code) {
this.code = code;
}
// ....
then when reading in data, create your County objects and as each Zip code is read in, add it to the appropriate County object using the addZipCode(...) method.
zipCode is an object of Type ZipCode then what are its fields? Think of the reasons for making it an object and not a variable
"Thus the loop may go thru n iterations, and construct n objects of type ZipCode"
Unforutnality this is not possible without making the use of Arrays
"structure that allows an inputted (scanned) string to be used as the name of an object"
Nope can do that.

When using Collections.sort - no instance of Variable T exist so that Collection conforms etc

so I've build these two classes:
1. Genre which implements Comparable
2. GenreManager which takes a Collection of genres and creates an internal copy of it. Later in GenreManager, I will need to add new Genres by getting a name as an input, and I need to assign this Genre the next free id number, which is basically the next smallest positive number after the smallest used id.
I am trying to use Collections.sort() to sort my list but I am getting the following error:
"no instance(s) of type variable(s) T exist so that Collection conforms to List." and I am not sure what this is referring to... I've tried ready a bunch of posts about this on here but couldn't figure out the solution... Here is part of the code:
public class Genre implements Comparable<Genre>{
private int id;
private String name;
public Genre(int id, String name){
this.id = Validate.requireNonNegative(id);
this.name = Validate.requireNonNullNotEmpty(name);
}
#Override
public int compareTo(Genre o) {
int res = Integer.valueOf(id).compareTo(o.id);
if (res != 0){
return res;
}
else{
return this.name.compareToIgnoreCase(o.name);
}
}
}
public class GenreManager{
private Collection<Genre> genres;
private Collection<Genre> sortedTree;
public GenreManager(){
this.genres = new ArrayList<Genre>();
}
public GenreManager(Collection<Genre> genres){
// check for duplicates
for (Genre x : genres){
for (Genre y : genres){
if (x.equals(y) || x.getName().equals(y.getName()))
throw new IllegalArgumentException("List contains duplicates");
}
}
this.genres = new ArrayList<Genre>(Collections.sort(genres));
}
}
I am trying to do the sorting in the constructor above. Can someone tell me how to go around this?
I tried playing around a little bit, trying to change the private variable from Collection<Genre> to List<Genre> for example and similar things but nothing worked... I also tried casting the input of the .sort method to (List<Genre>) but it didn't work either.
PS: I can't change any of the method header or class headers.
Thanks!
As per request, here's a compilation of my comments to answer the question:
The immediate problem is that Collections.sort(List<T>) takes a List parameter and not just a Collection because collections in general don't have to be sortable (e.g. hash sets aren't). Additionally the method returns void and sorts the passed list in place, i.e. the way you call it won't compile.
Taking all this into consideration your code might be changed to something like this:
public class GenreManager{
private List<Genre> genres;
...
public GenreManager(Collection<Genre> genres){
...
//create a list out of the passed collection
this.genres = new ArrayList<Genre>( genres );
//sort the list
Collections.sort(this.genres);
}
}
The other problem with the code you posted is that for any non-empty collection it will throw the IllegalArgumentException because elements are compared to themselves. Adding a check for x != y to the condition would solve that but the code is still somewhat slow because it has a time complexity of O(n2).
This can be solved to use a set instead of a list. However, a HashSet would depend on how equals() and hashCode() define equality, which doesn't seem to match your requirements. That could be solved by using a wrapper object that implements both methods as needed.
A better approach might be to use a TreeSet though. TreeSet uses comparisons to determine order and equality (if the compare result is 0) and thus would allow you to either let your Genre class implement Comparable as you did or provide a separate Comparator (e.g. if you need multiple different definitions of equality).
If you just want to eliminate duplicates, your code could then look like this:
public class GenreManager{
private SortedSet<Genre> genres;
...
public GenreManager(Collection<Genre> genres){
this.genres = new TreeSet<>( genres );
}
}
If you want to know what duplicates are in the collection you could do it like this:
public GenreManager(Collection<Genre> genres){
this.genres = new TreeSet<>(); //the generic type is inferred from this.genres
for( Genre element : genres ) {
//If the element didn't exist in the set add() will return true, false if it existed
boolean nonDuplicate = this.genres.add( element );
//handle the duplicate element here
}
}
As it was mentioned before, your code has several errors which makes it unusable:
Checking equality of elements with themselves.
Collections.sort method takes a List of Comparable as an argument, when Collection is a little higher in a hierarchy, which means you can't use it as a parameter. To resolve it change declaration of variable genres to List.
method Collections.sort returns void, so you can't pass its return value as an argument to ArrayList constructor. Instead, try assigning genres variable first and then sorting it via Collections.sort as
this.genres = new ArrayList/LinkedList(genres)
Collections.sort(this.genres)
Again, you may consider using TreeSet as it holds all elements sorted and without duplicates, so your constructor will just look like
this.genres = new TreeSet(genres)
In addition, it prevents duplicates even during adding, so if you have 10 elements, adding already existing one won't make any changes to your set. But using this data structure you should check variable for null before adding, as it will produce NullPointerException

Multiple instance of class versus array Java

My question which of the following examples represents the right practice ?
What are the advantages and downsides of these approaches.
Is there another(right) way to achieve this?
Let's say I have class
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String print() {
return this.name;
}
}
And use of class like:
public static void main(String[] args) {
List<Person> people = new ArrayList<Person>();
people.add(new Person("Jane Doe"));
System.out.println(people.get(0).print());
}
And then another way to do this:
public class Persons {
private ArrayList<String> persons;
public Persons() {
persons = new ArrayList<String>();
}
public void putPerson(String name) {
persons.add(name);
}
public String print(int id) {
return this.persons.get(id);
}
}
And use of that:
public static void main(String[] args) {
Persons persons = new Persons();
persons.putPerson("John Doe");
System.out.println(persons.print(0));
}
EDIT:
Assume I have 10 000 of these persons.
Is there any downside to creating 10,000 instances of the class?
I would prefer the first way because there is a rare need to create a wrapper class for keeping a collection (like Persons -> Person). It makes sense if the class Persons gets renamed to a Company/Community, which contains a List of workers/persons and provides specific operations over this list.
public String showAllMembers() { ... }
public void notifyAllMembers() { ... }
Also, the second way breaks the Single responsibility principle. It shouldn't take care about printing a person, the class is responsible for adding/removing them. The Persons can provide to you a specific Person, then you have to call a method print() on a given instance:
Persons persons = ...;
persons.getMember(10).print();
Lets say i have 10 000 of these persons. Is there any downside to create 10 000 instance of class?
In any case, you will have to create 10000+ instances. Consider,
10000 Persons + a List
10000 Persons + a Persons + a List
The first one is more object-oriented than the second, which becomes apparent as soon as you start adding more properties to a person.
For example, consider adding a date of birth to a person. When you have class Person, you modify the class, and everyone who has access to it will be able to get it. You will also be passing the date of birth with the Person object, so any method that takes Person as a parameter will have access to that person's date of birth:
static void displayPerson(Person p) {
// Here, we can print both the name and the date of birth / age
}
public static void main(String[] args) {
...
displayPerson(people.get(0));
}
The second approach would require adding a parallel collection to the Persons class. All users of Persons would get access to date of birth, but unless a method takes the full collection as a parameter, it would have access to only the properties that the caller takes from the collection:
void displayPerson(String name) {
// Here, we have no access to person's date of birth
}
public static void main(String[] args) {
...
displayPerson(persons.print(0));
}
In Java, the first approach is the one to go with. It is more in accordance with the OOP way of doing things.
While there is nothing structurally wrong with the second, it doesn't follow the OOP architecture. You may do this kind of operation in C.
In the first approach, you create a Person class which defines what a person is - its properties, methods, etc. This is the object in Object oriented programming. When you need a Person, you then instantiate one and add it to a list of people.
In the second, you create a array, essentially. You can then create an instance of it and fill in the properties you want. However, I see the following drawbacks for this approach:
The object you're adding to the class doesn't exist anymore. Nowhere have you defined what a person is and what properties it has. These properties only exist in the values you add to the array. This can get very confusing and risky after a while.
No getters and setters. Every operation to retrieve a specific property and update it will result in very complex and redundant iterations on your array. In addition, your class can potentially have a very large number of properties, and every time you want to update a property, you'll have to be very careful to get the right index of that property in the array. It's a recipe for disaster.
Also, a putPerson method which just adds a value to the array? Cringy.
Short answer: don't do the second way, in Java, ever.
In my opinion example A is much easier to understand than B hence I would say code readability and maintainability wise it is better.
Reason is that for example B the persons structure actually involves composition of another structure ArrayList to accomplish generics which in example A, you have achieve it by declaring List<Person>.
Example B is also less flexible than A, because it is always a collection whereas example A you can simply use it as a Person and just plug it into different data structures available in Java. Example if you want to keep track of unique person, you can easily come out with a map that is keyed by <name, Person>, whereas example B would not be as clean because you will be doing something like <name, Persons> where each persons would only contain 1 person. Hence extensiblity wise may not be as great as the other one.
Also to me, A is more of the traditional way of doing object oriented because you are representing a real world object as a class whereas B is really just a wrapper of an object.
Obviously there can be a lot of arguments to this, but I'm happy with others input and critic about this answer.

Java ArrayList: Adding object using string name

This is a very straightforward task, but I feel I'm overlooking something. I have multiple objects that I'm trying to add to an ArrayList, and each of them has an identifying name in the form of a String. I need to be able to find (interact) with the objects in the ArrayList by calling the string name. So I tried this:
In my item class I have:
private String itemName;
public Item(String name)
{
itemName = name;
}
So I can give it a name to be used by the user.
Then in my class that interacts with the object, I create an ArrayList:
private ArrayList<Item> items = new ArrayList<Item>();
I add an object to the arrayList first by it's actual object name, but I need to be able to interact with it using it's String name, so I tried this:
public void removeItem(String itemName)
{
for (int i = 0; i < items.size(); i++)
{
if (items.get(i).toString() == itemName)
{
items.remove(i);
}
break;
}
}
But it's not removing the item. If all of this is confusing, in essence I'm trying to create an OBJECT that I can give a STRING name (like I did with the item above), then have the ability to add the OBJECT to an ArrayList, and then finally be able to remove, or get, or do something with the OBJECTS in the ArrayList by calling the STRING name. I know I need to iterate through the ArrayList, but I can't actually get the object.
Thanks for any help.
You are dong three mistakes here:
You are using items.get(i).toString() which will not give you itemName for your Item. It will just give you a string representation of your Item class, returned by Object class's toString method, if you don't override one. However, this might work, if you have overriden a toString method, and returned the itemName from that. But, that I don't see. And even if you have overriden that, I suggest you to have getter and setter for your itemName field, and use that to return the itemName.
You are comparing strings using == operator, which will not give you correct result. You should always compare the string using equals method.
So, your if statement should look like:
if (items.get(i).getName().equals(itemName))
3rd problem is, you are trying to modify the List that you are iterating upon. This will not work out, and may throw ConcurrentModificationException. You should use Iterator to remove elements from the List while iterating.
See for more details about those two problems, and how to solve them:
How do I compare strings in Java?
Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop
Further, you can consider overriding equals method in your class, and then you can directly compare your instances using equals method.
Now, having pointed out the some logical problems with your code, it's time to point out some design problems.
Given your requirement, it seems like you need to use a HashMap, rather than a List of some custom type storing your attribute. You can create a map like this:
Map<String, Integer> map = new HashMap<String, Integer>();
which will contain the mapping of itemName to respective Item, and then getting the Item for a particular itemName is as simple as map.get(itemName).
It sounds like you should be using a Map for this, for instance java.util.HashMap<String, Item>. The Map interface provides exactly those operations you're looking for, and it is also iterable.
add a getter to your object to get the name, like so:
public class Item {
private final String name; //once given cannot change
public Item(String name) {
this.name = name; //yhis.name to distinguish between 2 variabled both called "name"
}
public String getName() {
return name; //this.name not required as no other variable called "name" is in scope
}
}
then you could find your Item like this:
for (Item item : theList) {
if (item.getName.equals(requiredName)) {
//got you!
}
}
generally speaking, dont ever compare strings with ==. also, if you want to remove an item from a list youre iterating over you have to use the (older) iterator syntax:
Iterator<Item> iter = theList.iterator();
while (iter.hasNext()) {
Item item = iter.next();
if (item.getName.equals(requiredName)) {
//got you!
iter.remove();
break; //no need to go over the rest of the list
}
}
and lastly, if all you want is to look up items by their name a list is not your best collection since finding the item may require traversing the entire list. maps (hashmap specifically) will give you much better performance for this type of operation. you could use the name as the key
my guess is that you items.get(i).toString() does not do what you think it does. Why don't you use some thing like items.get(i).name or create getters or setters for name in Item object and retrieve name by items.get(i).getName()
There is this - the way you implemented the removeItem, you can also do it directly using
ArrayList.remove(item.itemName)- that's just before you get all stuck up with ConcurrentModificationException and reimplementing stuff that already exists - look at the library!! Read the documentation of ArrayList!
For clarification: in Java (and mostly really only in Java): == means comparison of references.
So:
String a = "A";
String b = new StringBuilder("A").toString();
if (a == b) // --> false
if (a.equals(b)) // --> true
You could also consider using org.apache.commons.lang.StringUtils.equals for that - which is safe regarding null pointers.
As others already pointed out - the toString-method will only work correctly if you implement it correctly (returning the name in your case). By original toString returns a class-name together with an ID. That's probably not what you want (simply try to print it out).

Why is my Map broken?

Scenario: Creating a server which has Room objects which contain User objects.
I want to store the rooms in a Map of some sort by Id (a string).
Desired Behavior:
When a user makes a request via the server, I should be able to look up the Room by id from the library and then add the user to the room, if that's what the request needs.
Currently I use the static function in my Library.java class where the Map is stored to retrieve Rooms:
public class Library {
private static Hashtable<String, Rooms> myRooms = new Hashtable<String, Rooms>();
public static addRoom(String s, Room r) {
myRooms.put(s, r);
}
public static Room getRoomById(String s) {
return myRooms.get(s);
}
}
In another class I'll do the equivalent of myRoom.addUser(user);
What I'm observing using Hashtable, is that no matter how many times I add a user to the Room returned by getRoomById, the user is not in the room later.
I thought that in Java, the object that was returned was essentially a reference to the data, the same object that was in the Hashtable with the same references; but, it isn't behaving like that. Is there a way to get this behavior? Maybe with a wrapper of some sort? Am I just using the wrong variant of map?
Help?
It's very peculiar that you declare myRooms as Hashtable<String, Rooms> (plural Rooms), but you put a singular Room r in addRoom.
Are you trying to do some sort of multimap, where a key can map to a multiple values? If so, then either us the Guava implementation, or implement your own as a Map<K,Set<V>> (map a key to a set of values).
I'm not sure if this your fundamental issue, though.
It is correct that the returned value by get should be the same object, as defined by reference equality, as the one used in put.
Object someObject = new Object();
Map<String,Object> map = new HashMap<String,Object>();
map.put("key1", someObject);
System.out.println(map.get("key1") == someObject); // prints "true"
someObject = "something else";
System.out.println(map.get("key1") == someObject); // prints "false"
The above is expected behavior.
Sometimes people have trouble with a Map because their key objects do not implement hashCode and equals contract properly, but if you're using String as keys, this should not be an issue.
By the way, Hashtable has a newer, sexier cousin in HashMap. I noticed the multithreading tag in the question, so if you actually need the synchronized feature, you can use Collections.synchronizedMap
In either case, whether you use a HashMap or a Hashtable, you want declare myRooms simply as a Map (see Effective Java 2nd Edition, Item 52: Refer to objects by their interfaces).
Related questions
Overriding equals and hashCode in Java
Understanding the workings of equals and hashCode in a HashMap
Java hashmap vs hashtable
Difference between a Deprecated and Legacy API?
Does your code even compile?
public class Library {
private static Hashtable<String, Rooms> myRooms = new Hashtable<String, Rooms>();
public static addRoom(String s, Room r) { // Your hashtable holds Rooms yet you add a Room
myRooms.put(s, r);
}
public static Room getRoomById(String s) { // Again, returning a Room, instead of Rooms
return myRooms.get(s);
}
}
Just by looking at this, it shouldn't compile. Now I can only assume that it was a typo, and if that's the case then show us the Room code where you're trying to add a user to the room.

Categories