How to return HashMap object fields - java

I currently have the following HashMap in a Holiday class.
Holiday Class:
HashMap <String, Location> holidays = new HashMap<String, Location>();
This creates an instance of the Location class, to allow more fields to be shown.
Location class:
public class Location {
private String locationName;
private String locationDesc;
private double price;
private int quantity;
public Location(String locationName, String locationDesc, double price) {
this.locationName = locationName;
this.locationDesc = locationDesc;
this.price = price;
quantity = 0;
}
public String toString() {
return (locationName + " | " + "£" + price);
}
public double getPrice() { return price; }
public String getLocationName() { return locationName; }
public String getLocationDesc() { return locationDesc; }
public int getQuantity() { return quantity; }
}
In my GUI class I just use the .get HashMap method, this will return the toString.
e.g
GUI class
private Holiday holiday;
...
return holiday.holidays.get(--HashMap key here--);
this will return the toString, which is locationName and price.
However. I'm wanting to also print out the HashMap elsewhere, but with returning different fields. such as returning the Description and quantity as well as locationName and price. How would i go about doing this? Or how do i return the individual fields from the Location class which is an instance of in the HashMap.
MANAGED TO DO THIS. But need help with the following below
Second EDIT:
I have a set quantity method in my Location class, to set the amount of bookings for each holiday. However when using;
for (Location location : holiday.holidays.values()) {
location.setQuantity(Integer.parseInt(textFieldQuantity.getText()));
}
This changes all of the holidays to the same quantity when setting each location with a different quantity. How do i fix this?

The result of holidays.get(key) should be an object of type Location. If you print the object directly, like in System.out.println(holidays.get(key)) it will print the result of toString() as you say. But since you already have the object and access to its fields, you can print exactly what you want.
Something like this should work:
Location location = holidays.get(key);
System.out.println(location.getlocationDesc() + " | " + location.getQuantity());
Regarding your second question:
If you just need to print all values stored in your map, I think it would be cleaner and faster to iterate directly on the map values:
for (Location location : holiday.holidays.values()) {
System.out.println(location.getlocationDesc() + " | " + location.getQuantity());
}
Third question:
Note that your code does not set the quantity for only one location. It goes through all locations setting each quantity to the same value, defined by textFieldQuantity.getText().
If you want to modify a specific location, you need to retrieve it from the map using get():
Location location = holiday.holidays.get(key);
location.setQuantity(Integer.parseInt(textFieldQuantity.getText()));

Why not try something like:
private Location location = holiday.holidays.get(--HashMap key here--);
// Create a string with the variables
And then return the string.

this will return the toString, which is locationName and price
No. It will return an instance of Location. So all you have to do is
Location location = holiday.holidays.get("some key");
double price = location.getPrice();
String locationName = location.getLocationName();
Note that
you shouldn't use public fields. So it should be instead location.getHolidays().get("some key"). Or even better, to encapsulate the Map and respect the "don't talk to strangers" rule, location.getHoliday("some key").
Your getter should be named getLocationName() and not getlocationName() to respect the JavaBean conventions. Or even better, since this method is part of a Location class, the location prefix is redundant, and you should thus simply name it getName() (and getDescription() for the description)

Related

What's the best way to change attributes of objects stored in an ArrayList or HashMap?

I have to do a little exercise (homework, like a friendlist) in Java, and i'm a little stuck on one of the tasks that i have to implement in my program.
The exercise is about storing some friend-objects with a variety of attributes in a container-class and implementing some methods in the container-class for various tasks on the friend-objects.
The overall exercise is not a problem at all, but i'm quite unconvinced that my solution is the way to go. I hope you can give me some tips here.
The method that is left over, should be something like a "updateFriend" method, with which you can set the value of a given attribute to a new value, straight from the container-class.
I've already set up my friend-class with a handfull of attributes (e.g. prename, lastname, date of birth, adress, and so on) an getters/setters for all of them. I've also implemented the container-class (as an ArrayList), but i can't seem to find an elegant way to implement this specific method. My updateFriend()-method right now takes three parameters.
1.The specific id of the friend-object
2.The name of the attribute that i want to change
3.The new value of the attribute
It uses an enum to check if the entered attribute is an existing attribute and if yes, the method searches the ArrayList for the object that contains that attribute and should overwrite the existing value. It gets a little bulky, as i have implemented a switch on the enum, that calls the fitting setter-method for each attribute of the friend, if the type in attribute exists at all.
So basically the friend-class looks like this:
public class Friend {
private static int friendCount = 1;
private String firstname;
private String lastname;
private LocalDate dateOfBirth;
private String phonenumber;
private String mobilenumber;
private String eMail;
private Adress home;
private int friendID;
//Getters & Setters
...
}
The method that gives me problems in the container-class looks something like this at the moment:
public void updateFriend(int id, String toChange, String newValue)
{
for(Attribute a : attribute.values())
{
if(String.valueOf(a).equalsIgnoreCase(toChange))
{
for(Friend f : friends)
{
int counter = 1;
if(f.getID() == id)
{
switch(a)
{
case FIRSTNAME:
{
f.setPreName(neuerWert);
break;
}
//a case for each attribute
}
I'm quite certain that my take on the given method is messy, slow, and cumbersome. What would be an elegant way of solving this?
Excuse my wording and thanks in advance, greets.
I would suggest 3 performance improvements.
Use HashMap instead of List with key as id. Since, id will be unique, it will take O(1) time to get the relevant object for modification instead of spending O(n) time on List iteration.
You can change the type of toChange parameter from String to enum. This will avoid enum to String conversion and then comparing it.
Since, you are already doing validation of the attribute to be modified and you must be following standard java convention while naming your getters and setters, you can use reflection to call the method on the Friend object by creating the method name from attribute name like set{Attributename}.
Okay, lets start using the enum Attribute to handle all the changes (Since you already holding the attribute values)
Attribute Enum
public enum Attribute {
FIRSTNAME("fname", (friend, name) -> friend.setFirstname(String.valueOf(name))),
LASTNAME("lname", (friend, lname) -> friend.setLastname(String.valueOf(lname))),
DATEOFBIRTH("dob", (friend, dob) -> friend.setDateOfBirth((LocalDate) dob)),
PHONENUMBER("pno", (friend, pno) -> friend.setFirstname(String.valueOf(pno))),
MOBILENUMBER("mno", (friend, mno) -> friend.setFirstname(String.valueOf(mno)));
private String attributeName;
private BiConsumer<Friend, Object> attributeSetter;
public static Attribute getAttributeSetterByName(String attributeName) {
return Arrays.stream(Attribute.values())
.filter(attribute -> attribute.getAttributeName().equalsIgnoreCase(attributeName))
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("Invalid Attribute name - %s", attributeName)));
//.orElse(null);
}
//Getter, Setter & Args Constructor (Use Lombok to reduce Boiler Plate code)
}
Update Logic
public void updateFriend(int id, String toChange, String newValue) {
Attribute attribute = Attribute.getAttributeSetterByName(toChange);
for (Friend friend : friends) {
if (friend.getId() == id) {
attribute.getAttributeSetter().accept(friend, newValue);
break;
}
}
}
You can use a java.util.function.Consumer<T> object to change an object inside your container where you have all the type safety you get. Instead of having magic strings and string arguments for values, which might not be even for string fields, you can work directly on the objects type:
public void updateFriend(int id, Consumer<Friend> c) {
// find the friend object
Friend found = null;
for (Friend f: this.friends) {
if (f.getId() == id) {
found = f;
break;
}
}
if (found == null) {
throw new IllegalArgumentException("There is no friend object with the given id");
}
// use the friend object.
c.accept(found);
}
You can use this method like this:
container.updateFriend(42, f -> f.setVorName("abc"));
container.updateFriend(9, f -> f.setAddress(some_address_object));

How do I add an item from a class to an ArrayList?

I know the question seems weird, but I'll try to explain it the best that I can. I am doing an Amusement Park Project where you have methods for the tickets, merchandise, etc. I made a Ticket class with the methods, but now I'm in the AmusementPark class trying to create a method of taking the date from that class and putting it into a new ArrayList. Maybe my code will help explain it.
First, here is my Ticket class......
import java.text.DecimalFormat;
public class Ticket {
private long number;
private String category;
private String holder;
private String date;
private double price;
private boolean purchased;
Ticket(long num, String cat, String h, String dt, double pr, boolean pch){
this.number= num;
this.category= cat;
this.holder= h;
this.date= dt;
this.price= pr;
this.purchased= pch;
}
long getNumber(){
return number;
}
String getCategory(){
return category;
}
String getHolder(){
return holder;
}
String getDate(){
return date;
}
boolean getPurchased(){
return purchased;
}
double getPrice(){
return price;
}
void setPrice(double pr){
price= pr;
}
void setChangePurchased(boolean newStatus){
purchased= newStatus;
}
#Override
public String toString(){
DecimalFormat dm= new DecimalFormat("#.##");
String disp;
disp = "Number: " + getNumber() + "\nCategory: " + getCategory() + "\nTicket Holder Name: " + getHolder() + "\nDate: " + getDate()
+ "\nPrice: " + dm.format(getPrice()) + "\nPuchased Completed?: " + purchased;
return disp;
}
}
Here is some of the Pseudo Code explaining what I am trying to do with the next class I'm about to post.
Create an ArrayList from the Ticket class.
//The ticket class has the following constructors....
// (Ticket number of type long, category of type String, Ticket holder of type String, Date of admission, purchase price of type double, variable named "purchased" whether the ticket has been paid for of type boolean)
//One of the variables of type class is tickets in which the ticket class is made into an ArrayList.
//The next task is to get tickets for dates where they are available, which is done by searching tickets where the purchase is not completed.
Create a public ArrayList<Date> method called getTicketDates(){
Create a variable called theDateArray which is a new ArrayList<Date>;
For(starting at the first position of the list, go through the the entire list incrementing by one){
if (boolean purchased of the Ticket ArrayList is false)**{
Add the date of the object from the Ticket ArrayList to theDateArray ArrayList.}** //This stores the dates of all tickets not yet purchased into the new ArrayList.
}
Return theDateArray;
}
//The next task is to search through theDateArray for only select dates and post the available tickets for that date as an integer.
Create a method which displays the number of tickets for a specified date by going through theDateArray (Date date) {
For(starting at the first position of theDateArray, go through the entire list and look for tickets that have a particular date){
if (the date== entered date){
Include the ticket as one of the tickets available for that date.
}
}
Return the total number of tickets available for that date as a type integer.
}
Okay, now here is my AmusementPark class. Note It is not finished. I'm just trying to get this one part done....
import java.util.ArrayList;
import java.util.Date;
public class AmusementPark {
private ArrayList<Ticket> tickets;
private ArrayList<Merchandise> merchandise;
private String name;
AmusementPark(String name){
this.name=name;
this.tickets = new ArrayList<Ticket>();
this.merchandise= new ArrayList<Merchandise>();
}
String getName(){
return name;
}
public ArrayList<String> getTicketDates(){
ArrayList<String> theDateArray= new ArrayList<>();
int i;
String date = Ticket.getDate(); //This is not working. See Reason Below.
for (i=0; i<tickets.size(); i++){
if(tickets.get(i).getPurchased()== false){
theDateArray.add(date);
}
}return theDateArray;
}
}
Okay, so now what happens when I try to call the method of getDate() from the Ticket class, it's not allowing me to use it for the reason that I cannot make a static reference to a non-static method. However, when I try to make the method static, it messes up the other class by saying I cannot make a static reference to a non-static field.
An ArrayList of the Ticket class has already been made. I need it to scroll through that list, get the ones where the boolean is false, and add the date to the next ArrayList.
Does this at all make sense?
Any ideas that would be better?
Let's take your method.
public ArrayList<String> getTicketDates(){
ArrayList<String> theDateArray= new ArrayList<>();
int i;
String date = Ticket.getDate(); //This is not working. See Reason Below.
for (i=0; i<tickets.size(); i++){
if(tickets.get(i).getPurchased()== false){
theDateArray.add(date);
}
}
return theDateArray;
}
Notice the problem on the Ticket.getDate() that you try to do whithout an instance, so a static call. But what you explain, you want the date for the Ticket of the list tickets. Good, you are iterating it after but are pushing this strange value date coming from a "static method".
You problem is that the instance holding the date you want is in the list. You are using it to see if it is purchased or not. So call the method on those instance to get the value :
for (i=0; i<tickets.size(); i++){
if(tickets.get(i).getPurchased()== false){
theDateArray.add(tickets.get(i).getDate());
}
}
But better :
Ticket ticket;
for (i=0; i<tickets.size(); i++){
ticket = tickets.get(i);
if(ticket.getPurchased()== false){
theDateArray.add(ticket.getDate());
}
}
If I understand it correctly what is required here is to extract dates for not purchased tickets into separate dates array. And you already got it correctly in your pseudocode, you just need to follow it more strictly during implementation:
public ArrayList<String> getTicketDates() {
ArrayList<String> theDateArray = new ArrayList<>();
// iterate over all tickets
for ( Ticket ticket : tickets ) {
// if ticket not purchased
if ( ! ticket.getPurchased() ) {
// add ticket's date into array
theDateArray.add( ticket.getDate() );
}
}
return theDateArray;
}
DON'T MAKE STATIC REFERENCE !Instead of writing a what's code answer let's focus on the workaround of problem.
Whenver you will set values to instance variables of TICKET Class it will refer to a particular object (new ticket()) to access its values if you make variables of class staticValues will be stored when class is loaded and not when object is created but arraylist items need to have
Object of ticket Class.
A simple approach should be
ASSIGN THE VALUES TO VARIABLES WHEN EVER YOU MAKE AN OBJECT OF TICKET CLASS BY BY PASSING VALUES IN ITS CONSTRUCTOR AND THEN
ADD THOSE OBJECTS TO ARRAYLISTITEMS
ticket class
public class Ticket {
private long number;
private String category;
private String holder;
private String date;
private double price;
private boolean purchased;
Ticket(long num, String cat, String h, String dt, double pr, boolean pch){
this.number= num;
this.category= cat;
this.holder= h;
this.date= dt;
this.price= pr;
this.purchased= pch;
}
make a new object and pass values
Ticket t1=new Ticket(3,"yourstring","yourstring",yourDouble,true/false);
add items in arrayliSt:
List<Tickets> tList=new ArrayList();
tList.add(t1);
tList.add(t2);
//and so on
now retrive values from arralylist
Ticket t=tlist.get(0);
t.cat;
t.whatevrbe thevalue be

Return two string in toString function

#Entity
public class Person {
private Integer id = null;
private String name = null;
private String price = null;
private Date created = null;
// String Representation:
#Override
public String toString() {
return name;
// I want to return name and price
}
I want to return name and price in toString function ? This is right to return more than one string in toString function. If you make relation in other's Entity ManyToMany ?
Please suggest me if I am doing right or wrong as I want to show these fields in other entity where I make relations.
Thanks!
Usually the toString() method returns a string-representation of the object and not the object's members themself. So if you need a representation of name and price you could do
return "Name: " + name + ", Price: " + price;
If you really want to receive the members name and price you should generate getters for those and use them in the caller.
Another possibility is to "wrap" the two strings in some sort of data class.
This is right to return more than one string in toString function. If you make relation in other's Entity ManyToMany ?
That could be
#Override
public String toString() {
return "Name :" +name + " Price : "+price;
}
If you still have more Objects related to it, just append in the last. So that you won't loose information.
You can do it like this:
return name+" "+price;
You can create another method to return both.
you can return String array as well so that you don't need to split the string if you need to perform any operation on name and price.
You can use a StringBuilder and build up your composed String efficiently from both the name, the price and whatever you want.
Here the documentation.
Anyway, the response is no, you cannot send back two strings, but you can return a string that is a composition of the others.

How do I add or subtract String values to an object, and set the value to "none" when it's empty?

I have a class Passengers which has member properties String name, int health, and String disease with setter and getter methods. The disease variable will initially hold null. Here's that class
public class Passengers
{
private String name;
private int health;
private String disease;
public Passengers(String _name, int _health, String _disease)
{
name = _name;
health = _health;
disease = _disease;
}
public void setHealth(int _health)
{
health = _health;
}
public void setDisease(String _disease)
{
disease = _disease;
}
public String getName()
{
return name;
}
public int getHealth()
{
return health;
}
public String getDisease()
{
return disease;
}
}
What I want to know is how I could add new strings onto this variable, and then how to take away. For example, a passenger Bill starts at null for his diseases, and then contracts malaria and the cold. Bill's disease variable should now hold malaria, cold. Now say the user chooses to treat Bill's malaria. How would I
1) add malaria and cold
2) subtract just malaria from disease?
Whenever I attempt to change the disease with
passengers[index].setDisease() = null;
it says "error: method setDisease in class Passengers cannot be applied to given types:
required: String
found: no arguments"
I would reccomend making disease a Set of Strings.
Set<String> diseases = new HashSet<String>();
void addDisease(String disease) {
diseases.add(disease);
}
void removeDisease(String deisease) {
diseases.remove(disease);
}
Sets are "better", in this case, than other Collections because they cannot hold duplicates.
You should give the class a List<String> such as an ArrayList<String> and put the diseases in this List.
Better still, create a class or enum of Disease and have your Passenger class use a List<Disease> and avoid over-use of String. You could then give the class public addDisease(Disease disease) and removeDisease(Disease disease) methods.
Incidentally, your class above should be named Passenger, the singular, not Passengers, the plural, since it represents the concept of a single Passenger.
For your requirement if you are using List like ArrayList you can access your elements(disease names) by index, but it will allow duplicate data to be inserted(same disease may be added multiple times, it will unnecessary increase in number of diseases and may arise some problems).
If you use Set like HashSet it will allow unique element only, so no issues related to duplicated entries but at the same time you can't access a particular disease by index (if you need so, as of now I am not aware of your further requirement).
So as best of my knowledge I suggest you to use LinkedHashSet(HashSet with Linked approach) it will provide you FIFO order without duplicate insertion problem.

Getting object values from a LinkedHashMap

So for my local data structure I have the following
DataStructure ds = new DataStructure();
//Examples to put in the Data Structure "ds"
ds.menu_item.put("Pizza", new DescItems("A Pizza",2.50,4));
ds.menu_item.put("Hot Dog", new DescItems("A yummy hot dog",3.50, 3));
ds.menu_item.put("Corn Dog", new DescItems("A corny dog",3.00));
ds.menu_item.put("Unknown Dish", new DescItems(3.25));
The DataStructure class has a LinkedHashMap implementation such that
LinkedHashMap<String, DescItems> menu_item = new LinkedHashMap<String, DescItems>();
And finally the DescItems class is
public final String itemDescription;
public final double itemPrice;
public final double itemRating;
public DescItems(String itemDescription, double itemPrice, double itemRating){
this.itemDescription = itemDescription;
this.itemPrice = itemPrice;
this.itemRating = itemRating;
}
There are other constructors to account for no itemDescription and/or itemRating
I'm trying to apply a method to check to see if a value has itemRating other than 0 (0 indicating no rating)
But specifically I came across this problem:
DescItems getC1 = (DescItems)ds.menu_item.get("Pizza");
System.out.println(getC1.toString());
Only prints out reference information like DescItems#142D091
What should I do to get a specific object variable instead of referencing the object?
You need to Override the toString() method in DescItems
Something like this:
#Override
public String toString() {
return itemDescription + " " + itemPrice + currencySymbol + " (" + itemRating + ")";
}
You can override the toString() method in your DescItems class. For example:
public class DescItems {
. . .
#Override
public String toString() {
// whatever you want here
return String.format("%1$s (price: $%2$.2f; rating: %3$f)",
itemDescription, itemPrice, itemRating);
}
}
The default implementation of toString() returns an object identification string like what you are seeing.
An alternative is to print the exact field(s) you want:
System.out.println(getC1.itemDescription);
You just need to override the toString() method to return the text that you want.

Categories

Resources