If I need to capture the name (first, middle and last) of a Person, I thought of the following possibilities:
Use a Map<String, String> name;
Use a separate Name class.
If I use a Map, I can store the names like this:
name.put("first", "xyz")
name.put("middle", "abc")
name.put("last", "nhf");
Then in the Person class:
class Person
{
Map<String, String> name;
//below write setter and getter for it.
}
If I use a Name class, I can store like this:
class Name
{
String first;
String middle;
String last;
//Below write setters and getters for them.
}
Then in the Person class:
class Person
{
Name name;
//below write setter and getter for it.
}
I wanted to know which one is a better way of doing and why. Also if there is any other better way of doing this.
Maps are great for flexibility. I.e., if you don't know exactly what keys you're going to have. E.g., if one person will have a Christian name, another will have a nickname and a third will have a paternal and maternal surnames, a Map may make sense. In your example, everybody has a first, middle and last name (although some of them may possibly be null?), so a map just adds redundant complication (as as noted here on the thread, memory consumption). Frankly, unless you have some special use for the entire Name as an object (e.g., using it as a key in a map), I'd just place three string members directly in the Person class.
This is entirely up to you -- there is no "best" answer here. It depends on how you are using the class.
Generally you do not want to hide things in a map like that. It makes more work to ensure things are correct. What if you accidentally add an incorrect key to the map? Your data structures could get out of whack easily with that method.
Personally, I would most likely just have the 3 values on the Person class directly and not bother with a Name class or a Map.
Once again, I am using words like "most likely" and "generally" because I do not know how the class is being used.
Creating a map is quite memory consuming, compared to creating a name class.
It's better to create the name class, (for one thing, less lines of code :P), mainly because it's less prone to be changed mid-run, unlike the map.
The entries in a map might be accidentally changed during runtime, which could cause problems. If the Name class doesn't have setters, then this can't happen.
Related
Problem
I want to know if this is possible if I could create a State machine that would contain all the methods and the Values of MethodById would be stated in the machine.
P.S. this is my first question ever on here. If I do it wrong I'm sorry but that is why.
Description (TL;DR)
I'm trying to cross reference data about Sales representatives. Each rep has territories specified by zip-codes.
One dataset has the reps, their territories and their company.
Another data set has their names, phone number and email.
I made a Sales-rep class that takes from the first data-set and needs to be updated with the second data-set.
I also need the Sales-reps to be put in a look-up table (I used a hashmap for this) of <key: zip code, value: Sales-rep object>.
What I want is for each Sales-rep object to having an ID that is standard across all my datasets. I can't use the data I'm provided with because it comes from many different sources and its impossible to standardize any data field.
Names, for example, are listed so many different ways it would be impossible to reconcile them and use that as an ID.
If I can get an ID like this (something like an SSN but less sensitive) then I want to try what my question is about.
I want to iterate through all the elements in my <key: zip code, value: Sales-rep object> hashmap, we will call it RepsByZipCode. When I iterate through each Salesrep object I want to get an ID that I can use in a different hashmap called MethodById <key: ID, value: a method run on the Object with this ID>.
I want it to run a different method for each key on the Object with the matching key (AKA the ID). The point is to run a different method on each different object in linear time so that by the end of the for loop, each object in RepsByZipCode will have some method run on it that can update information (thus completing the cross-referencing).
This also makes the code very extendable because I can change the method for each key if I want to update things differently. Ex:
//SalesRep Object Constructor:
SalesRep(String name, String email, ..., String Id)
Map<String zipcode, Salesrep rep> RepsByZipCode = new HashMap<>{}
//code fills in the above with the first dataset
Map<String ID, ??? method> MethodById = new HashMap<>{}
//code fills in the above with the second dataset
for(String ZipKey:RepsByZipCode){
Salesrep Rep = RepsByZipCode.get(ZipKey);
Rep.getId = ID;
MethodById.get(ID);
//each time this runs, one entry in RepsByZipCode is updated with one
//method from MethodById.
//after this for loop, all of RepsByZipCode has been updated in linear time
You could put these methods into different classes that implement a common interface, and store an instance of each class in your map. If you're using at least Java 8 and your methods are simple enough, you could use lambdas to avoid some boilerplate.
starting out with Java and have run into some issues.
I have created a class called: Admin, which a user will give attributes to such as a name and other pedigree info...but the main function of the Admin class is to create arrays that will be used as a queue system.
I am trying to allow the Admin to create as many arrays as they desire. However I am having trouble figuring out a way to differentiate between each of the arrays when it comes to reiterating them back to the user.
For instance, lets say an "Admin" was a Bank and wanted to create an array that a "User"(i.e. customer, which has it's own class) could join to get in line to see a teller.
The Bank may also want to create a line for a "User" to see a Loan Officer, etc.
I am not able to allow the Admin to give each array a specific reference variable that would differentiate it from others by doing this:
System.out.println("Enter the name of the line you wish to create: ");
String lineName=keyboard.nextLine();
ArrayList<User>lineName=new ArraryList();`
The program gives an error saying that the variable has already been initialized in the method when I do so, which I kind of understand. However having the functionality of knowing what line I am looking at within the code is invaluable to me.
Another reason I wish to do this is because I want to create an Array of Arrays that would show a customer all of the "lines" they could potentially join. So I would like the output to look something like this:
John Hancock Bank lines:
Teller Window
Loan Officer
Mortgage Specialist
etc.
From there I would allow the user to access the element of the array they wish to join.
What would be the best way to "identify" each specific array that is created by an Admin?
Typically, variable names have meaning to a programmer, and not to a user.
If you want to associate a list with a name, you'd either want to use a Map like so:
Map<String, ArrayList<String> lines = new HashMap<String, ArrayList<String>>();
lines.put(keyboard.nextLine(), new ArrayList<String>());
Or create a new class to model this association:
class Line{
String lineName;
ArrayList<String> people;
public User(String name, ArrayList<String> people){
this.lineName = name;
this.people = people;
}
}
The comments are above are right though. I think a Queue would be better for your purpose.
You could use a HashMap.
Map<String, List<User>> map = new HashMap<String, List<User>>();
System.out.println("Enter the name of the line you wish to create: ");
map.put(keyboard.nextLine(), new ArraryList<User>());
The error about the you're getting about the variable that has already been initialized is due to you reusing a variable name as follows:
String lineName=keyboard.nextLine();
ArrayList<User> lineName=new ArraryList();`
You have created two variables but they have the same name. Each variable must have an unique name - otherwise when you later refer to lineName there's no way to know if you mean the String or the ArrayList.
As other have noted, in general when you want stuff like a "line" that has a "line name" and a value, the correct data type to store this information is a map. A map consists of key-value pairs, where the key is the "line name" and the value is the actual data.
You'll notice people putting a lot of emphasis in choosing the correct data type and structure for storing your information. This is a very core concept in programming: choosing the correct data structure and type to use is extremely important in producing effective and good code and it's best to grasp these concepts well from the get-go.
Usually I'd love all my POJOs to be immutable (well, to contain only final fields as Java understands immutability). But with my current project, a constant pattern is that I need to change a single field from a POJO. Working with immutable POJO's in this scenario seems cumbersome.
How would you go about having POJO's with bunch of fields and for each field you should be able to say "please give me a copy of this POJO but with this one field changed"?
Big plus here would be something that I can use with composable Functions. "Start with this immutable pojo, then basically push it through bunch of UnaryOperators and give me back new immutable pojo".
Yes, that's a fairly common pattern - usually with a bunch of methods with a with prefix. Each with* method "changes" a single field, so you can have:
Person jon = new Person("Jon", "Skeet");
Person holly = jon.withFirstName("Holly"); // Holly Skeet
You can chain the calls together, too:
Person fred = jon.withAge(...).withFirstName("Fred").withJob(...);
Note that if you end up changing K fields in a POJO with N fields, you'll create K objects and need K * N assignments.
The implementation is usually just a matter of calling a big constructor with the existing field values and the new one:
public Person withFirstName(String newFirstName) {
return new Person(newFirstName, lastName, job, age, ...);
}
I've used the term "pseudo-mutator" for this kind of method - it's a method which sounds a bit like it's mutating something, but it's more like it's creating a clone, mutating the clone, then returning it to you in a "frozen" state.
I need a Map that takes Key-Value pair (probably HashMap<String, Object>) whereas the Key will be a property of the Object itself, like:
class Person {
String name; //I know a string is not a good unique key, but ok to illustrate my example
}
Person person = new Person("John");
map.put(person.getName(), person);
Further, the map must provide an accessor similar to ArrayList.add(idx, object). It should thereby also be possible to reorder an object to a different position and adjust the rest accordingly.
Which Map/List is suitable for this?
(by the way: I should be runable with GWT, so external libs might be problematic).
There's no single standard container that does all of this.
However, a combination of a map and an ArrayList would satisfy all of your requirements.
I'm writing a program with a bunch of classes that will be serialized to save in a database and to be sent through a network.
To make things easier for accessing the class properties via command line interface, I'm considering storing the properties in a Map class, instead of giving each property it's own variable.
Basically, instead of using something like this:
String id = account.getUserId();
I would do this
String id = account.properties.get("userId");
Is this an advisable way to do things?
Yes, it's a pretty sensible model. It's sometimes called the "prototype object model" and is very similar to how you would work in JavaScript where every object is effectively a Map. This in turn has led to the very popular JSON serialisation format.
Nice features:
You don't have to worry about messy inheritance heirarchies - you can just alter the properties at will.
You can create a new object just by copying from another object (the prototype)
Code to manipulate the data can do so in a uniform way, without having to explicitly name all the variables.
It's more "dynamic" compared to a static class definition - it's easy to extend and modify your objects
Potential risks / downsides:
You need to keep track of your property names if you use Strings - the compiler won't do it for you! This issue can be alleviated by using Enums as keys, but then you lose some flexibility...
You don't get the benefits of static type checking, so you may find that you need to write more JUnit tests as a result to ensure things are working properly
There is a slight performance overhead (though probably not enough to worry about, as map lookups are very fast)
I actually wrote an entire game in the 90s using a variant og this object model (Tyrant) and it worked very well.
Rather than having a Map object exposed however, you may want to consider encapsulating this functionality so that you can use an accessor method on the object itself, e.g.
String id = account.getProperty("userId");
How I prefer to do this is often like this:
enum StringPropertyType {
USERID, FIRSTNAME, LASTNAME
}
interface StringAttributes {
String get(StringPropertyType s);
void put(StringPropertyType s, String value);
}
class MapBasedStringAttributes implements StringAttributes {
Map<StringPropertyType, String> map = new HashMap<~>();
String get(StringPropertyType s) { return map.get(s); }
void put(StringPropertyType s, String value) { map.put(s,value); }
}
this gives you compile-time safety, refactoring, etc.
you could also use the stringPropertyType.name() to get the string representation of the enum value and use
Map<String,String>
instead..