Coding practice - Which coding approach should I use? - java

Sorry for such a vague title. Did not think of good one.
Situation:
Have a List of User objects.
Need to create array for UserInfo object.
UserInfo object is created is based on information in User object. (Currently has a method for this)
Which is better in such a situation?
Should I pass whole list of User to User to UserInfo conversion method.
or Should I loop over list of User and pass each user object to conversion method and get UserInfo for it.
Examples:
List<User> users = .....;
UserInfo[] userInfos = getUserInfoFromUser(users); //(conversion method will loop and generate array, then return it.)
or
List<User> users = .....;
UserInfo[] userInfos = new UserInfo[users.size()]
for (int j = 0; j < users.size(); j++) {
userInfos[j] = getUserInfoFromUser(users.get(j));
}
In first approach we pass a big object(list of User) as an argument and in second we call same method multiple times.Which is better?
The size of User list will be range from 25-200 objects in it.

How about having two conversion methods, one that takes a User and returns a UserInfo (this could and probably should be a constructor of UserInfo), and one that takes a List, does the looping and internally calls the first one?
The size of the list is not relevant.

I think it depends on how often you will doing this, because you don't want to repeat the same loop in multiple places in your code.
I would suggest creating two methods, one which returns the info for a single user and the other which returns info for a list of users:
public UserInfo[] getInfoForUsers(List<User> users) {
UserInfo[] userInfos = new UserInfo[users.size()];
for (int j = 0; j < users.size(); j++) {
userInfos[j] = getInfoForUser(users.get(j));
}
return userInfos;
}
public UserInfo getInfoForUser(User u) {
}

I prefer the first approach as it is simple, also, argument will be the address of the users object. So doesn't matter big or small in that case.

In the both cases, Java passes reference to an object. In 1st case, it's reference to collection of Users and in 2nd to an User.

I would recommend to use the first option: pass the whole array!
Reducing the number of function calls definitely pays out.

There is no difference: in the first version the function implementation would do the second version. Furthermore probably would like to have a function User -> UserInfo.

Related

How can I replace object in java collection?

I am trying to replace element in collection with new modified version. Below is short code that aims to demonstrate what I'd like to achieve.
The whole idea is that I have one object that consists of collections of other objects. At some point in time I am expecting that this objects in collections (in my example phones) might require some modifications and I'd like to modify the code in one place only.
I know that in order to update the object's attributes I can use setters while iterating through the collection as demonstrated below. But maybe there is better, more general way to achieve that.
public class Customer {
private int id;
private Collection<Phone> phoneCollection;
public Customer() {
phoneCollection = new ArrayList<>();
}
//getters and setters
}
and Phone class
public class Phone {
private int id;
private String number;
private String name;
//getters and setters
}
and
public static void main(String[] args) {
Customer c = new Customer();
c.addPhone(new Phone(1, "12345", "aaa"));
c.addPhone(new Phone(2, "34567", "bbb"));
System.out.println(c);
Phone p = new Phone(2, "9999999", "new name");
Collection<Phone> col = c.getPhoneCollection();
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
// This is working fine
// phone.setNumber(p.getNumber());
// phone.setName(p.getName());
// But I'd like to replace whole object if possible and this is not working, at least not that way
phone = p;
}
}
System.out.println(c);
}
}
Is this possible to achieve what I want?
I tried copy constructor idea and other methods I found searching the net but none of them was working like I would expect.
EDIT 1
After reading some comments I got an idea
I added the following method to my Phone class
public static void replace(Phone org, Phone dst){
org.setName(dst.getName());
org.setNumber(dst.getNumber());
}
and now my foreach part looks like that
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
Phone.replace(phone, p);
}
}
And it does the job.
Now if I change the Phone class attributes I only need to change that method. Do you think it is OK solving the issue that way?
You should not modify the collection while you're iterating through it; that's likely to earn you a ConcurrentModificationException. You can scan the collection for the first object that matches your search criterion. Then you can exit the loop, remove the old object, and add the new one.
Collection<Phone> col = c.getPhoneCollection();
Phone original = null;
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
original = phone;
break;
}
}
if (original != null) {
Phone replacement = new Phone(original);
replacement.setNumber(p.getNumber());
replacement.setName(p.getName());
col.remove(original);
col.add(replacement);
}
Alternatively, you could declare a more specific type of collection, such as a List, that would allow you to work with indexes, which would make the replacement step much more efficient.
If your phone IDs are unique to each phone, you should consider using a Map<Integer, Phone> that maps each phone ID to the corresponding phone. (Alternatively, you could use some sort of third-party sparse array structure that doesn't involve boxing each ID into an Integer.) Of course, if your IDs aren't unique, then you might want to modify the above to gather a secondary collection of all matching phones (and reconsider the logic of your existing code as well).
You can also use a Set (HashSet), this is only when you don't want to do the way Mike suggested.
Use the Phone as an item in the set. Don't forget to implement hashCode() and equals() in Phone. hashCode() should return the id, as it is supposed to be unique.
Since you are concerned about replacing the item, here's how HashSet will help you :
Create an instance of your object.
Remove the object you want to replace from the set.
Add the new object (you created in step 1) back to the set.
Both these operations 2 & 3 are guaranteed in O(1) / constant time.
You don't need to maintain a map for this problem, that's redundant.
If you want to get the object from the collection itself and then modify it, then HashMap would be better, search is guaranteed in O(1) time.
Instead of a list, use a map with the Phone's id as the key. Then your code looks like this:
public static void main(String[] args) {
Customer c = new Customer();
c.addPhone(new Phone(1, "12345", "aaa"));
c.addPhone(new Phone(2, "34567", "bbb"));
System.out.println(c);
Phone p = new Phone(2, "9999999", "new name");
Map<Integer, Phone> phoneMap = c.getPhoneMap();
phoneMap.put(p.getId(), p);
System.out.println(c);
}
If you take the object out from the collection and update its properties, it will get reflected in the same object in collection too.. Hence, you dont have to technically replace object after updating it.
As "Mike M." pointed out, you can use hashmap to retrieve the object quickly without iteration and update the object values.
If order matters to you, you can change Collection to List (Since you're always using an ArrayList anyway) and then:
int index = col.indexOf(phone);
col.remove(phone);
col.add(p, index);

Accessing variable of ArrayList inside class

The class Task is describing tasks for a business which includes the variables: date, description, total amount of hours the task will take to complete, and the owner of the task.
An ArrayList is created for all the tasks named tasks. The problem is that a task can have more than one owner, meaning that creating a variable called owner wont work, so what I've done is that I created another class called TaskOwner and implemented that class as an ArrayList named taskOwner inside the Task class.
Now to the problem: You are supposed to be able to list tasks by a specific owner: meaning that you need to compare owners to the name you enter on your keyboard.
The problem in this lies within these lines of code:
System.out.println("What name of owner do you want to list tasks for: ");
String nameOfOwner = keyboard.nextLine();
if (nameOfOwner.toLowerCase().equals(tasks.get(1).getTaskOwner().getName().toLowerCase())) {
System.out.println(tasks.get(1));
}
I can't seem to access the variable named name inside the class TaskOwner, even though I've created getters for everything that is needed, so does anyone know how I am supposed to be able to access this information?
The error message I get is:
The method getName() is undefined for the type ArrayList
getTaskOwner appears to return an object of type ArrayList and not TaskOwner (that's what the error message indicates). In other words, it returns a list of owners. To call the getName() method, you need to loop over this list, and call the method on each element corresponding to an instance of TaskOwner.
System.out.println("What name of owner do you want to list tasks for: ");
String nameOfOwner = keyboard.nextLine();
for(int i = 0; i < tasks.size(); i++) {
List<TaskOwner> owners = tasks.get(i).getTaskOwner();
for(TaskOwner owner : owners) {
if (nameOfOwner.toLowerCase().equals(owner.getName().toLowerCase())) {
System.out.println(tasks.get(i));
break;
}
}
}
This returns an ArrayList:
tasks.get(1).getTaskOwner();
So you will need to call array list methods on it such as contains(...)
if (tasks.get(1).getTaskOwner().contains(nameOfOwner.toLowerCase())) {
As pointed out in other answers, the problem is you are calling getName() on an ArrayList<> instead of an object inside the ArrayList. The correct way of doing this would be to loop over all the tasks and then for each task, loop over their owners. Here is a sample piece of code, assuming the owners name is stored in the variable nameOfOwner:
for(Task task: tasks) {
for(TaskOwner owner: tasks.getTaskOwner) {
if (nameOfOwner.toLowerCase().equals(owner.getName().toLowerCase())) {
System.out.println(task);
break;
}
}
}
If you have also overloaded the equals method in the class TaskOwner to do a string match for the owner's name, you could just use the Arraylist.contains() method. But then, you will need to create a TaskOwner object out of the user input.
If your intention is to do task and owner lookups, you should also consider using HashMap. This would give you a better performance than ArrayList<> for direct lookups.

Fill an Array with different data types

i need to fill an Array with different data types
InvoiceItem[] invoiceItems;
int test = 3;
int i = 0;
This needs to be in the Array:
InvoiceItem invoiceItem = new InvoiceItem();
invoiceItem.setItemType("TestItem");
invoiceItem.setArticleNo("TestItemID");
invoiceItem.setDescription("TestDescription");
invoiceItem.setQty(1);
invoiceItem.setPrice(new BigDecimal(20.00));
invoiceItem.setVat(new BigDecimal(5.0));
There is the possibility that there is more than one InvoiceItem (test=3), so it needs to be in a loop.
It has to be an Array, i need to pass it to another class which only accepts an Arrays.
How can i achieve this?
Edit: I will try to make my question more clear:
I need to know how to put these
invoiceItem.setItemType("TestItem");
invoiceItem.setArticleNo("TestItemID");
invoiceItem.setDescription("TestDescription");
invoiceItem.setQty(1);
invoiceItem.setPrice(new BigDecimal(20.00));
invoiceItem.setVat(new BigDecimal(5.0));
in an Array:
int countofInvoiceItem = 3; // there are 3 InvoiceItem
InvoiceItem[] invoiceItems = new InvoiceItem[countofInvoiceItem];
Where there can be more than one InvoiceItem.
Method looks like this:
public final ResponseCreateInvoice CreateInvoice
(Invoice Invoice, InvoiceItem[] InvoiceItems, Address DeliveryAddress, Address InvoiceAddress, String UserID, String Password)
(This is given and i can not change)
and returns
ResponseCreateInvoice inv = wsClient.createInvoice(invoice, invoiceItems, deliveryAddress, invoiceAddress, userID, password);
i am sort of new to Java (or arrays), so this may be an easy question, but i don't really get it. Also does it matter that there are Strings and Int, BigDecimal etc mixed together in an Array?
You just need to declare your array as an array of type T where T is a superclass of all the classes of the objects you want to fill it with. In the worst case, it would be Object but it's bad design 9 times out of 10.
I would recommend you to make a class that holds everything you need as follows:
public class YourClass{
int id;
double value;
String description;
//and so on
//create getters and setters
}
And you can use this class to pass array of objects to another class.
Put your objects of the class in the Array
For example
YourClass[] objects = new YourClass[SIZE];//define number of objects you need
And you can pass each and every objects separately or as a whole to another class.
And in your receiving class, you can have a constructor as:
public YourRecievingClass(YourClass[] object){
//and recieve here as you need; ask further if you need help here too
}
I think this is the best way to adopt though your question is not 100% clear
Based on your edit, your original question is off base. You do not want to create an array of different types but instead only want to create an array of one type and one type only, that being an array of InvoiceItems. You are confusing object properties with array items, and they are not one and the same. This code here:
invoiceItem.setItemType("TestItem");
invoiceItem.setArticleNo("TestItemID");
invoiceItem.setDescription("TestDescription");
invoiceItem.setQty(1);
invoiceItem.setPrice(new BigDecimal(20.00));
invoiceItem.setVat(new BigDecimal(5.0));
is where you are changing the properties of a single InvoiceItem.
It seems that your InvoiceItem class has String fields for item type, for article number, for description, an int field for quantity, a BigDecimal field for price and a BigDecimal field for VAT. And so your array would look simply like:
InvoiceItem[] invoiceItems = new InvoiceItem[ITEM_COUNT]; // where ITEM_COUNT is 3
You could use a for loop to then create your items:
for (int i = 0; i < invoiceItems.length; i++) {
invoiceItems[i] = new InvoiceItem();
}
And you could perhaps use the same for loop to fill in the properties of each InvoiceItem in the array:
for (int i = 0; i < invoiceItems.length; i++) {
invoiceItems[i] = new InvoiceItem();
invoiceItems[i].setItemType(???);
invoiceItems[i].setArticleNo(???);
invoiceItems[i].setDescription(???);
invoiceItems[i].setQty(???);
invoiceItems[i].setPrice(???);
invoiceItems[i].setVat(???);
}
But the unanswered question is, ... where do you get the data for each property of each InvoiceItem in the array? Is this information contained in a file? Is it inputted by the user? That is something you still need to tell us.
With which types of data? In general, you could use:
Object[] myArray;
All classes are subclasses of Object.

Calling an Instance method when user inputs the instance name as a String

In a small project I am working on I've gotten stuck. The user enters a command that may be "xp Speed", my command handler class finds that it wants to the XP value of the Speed Instance. In this case it needs to return the value of Skill.Speed.currentXP back to the user.
Small Part of the program:
//Example Instance initialization there is over 40 of these
Skill Speed = (new SkillSpeed(Skills.SKILL_SPEED,Skills.SKILL_SPEED_MODIFIER));
//Constructor for skill class
public Skill(String skillName, double modifier) {
this.name = skillName;
this.minLevel = Skills.MIN_SKILL_LEVEL;
this.Modifier = 1f;
this.currentLevel = (int)calculateLevel();
this.currentXP = 1;
this.leaderboard = getCurrentLeaderboard();
this.ID = getNextID();
}
Now, theres one way i could do this. by having a switch statement with case value being the string entered. However I'm sure having 40+ cases in one switch statement must be avoidable. The other theory I have had is creating a array of all current instances then iterating through that list, finding if the user inputted string is equal to the name of that instance, then returning the instance itself. This is what I came up with:
//method inside another classs that attempts to return the appropriate skill Instance
public Skill getSkillFromName(String Name) {
for(int i = 0; i < Skill.SkillArray.length; i++) {
final String SkillName = Skill.SkillArray[i].getName();
if(SkillName.equalsIgnoreCase(Name)) {
return Skill.SkillArray[i];
}
}
return null;
}
So here's what I need help with:
Creating a array of all initialized instances
Creating the method that will return Skill."InsertRandomInstanceDependingOnUserInputHere".currentXP
Fixing any problems you see in the getSkillFromName() method
Or perhaps I have overlooked a far easier way of doing this, and you can help me with that.
Thanks for the help,
BigDaveNz
If the names of the skills excatly match method names you might find the aswer at "How do I invoke a Java method when given the method name as a string?".
For finding instances by name you can still use Map's.
You can use a Map for this. E.g.:
Map<String, Skill> skills = new HashMap<String, Skill>();
To insert the values you put the values into the Map:
skills.put(skill.getName(), skill);
To retrieve your skill you can get the skill by name:
Skill skill = skills.get(name);

Is there a fixed length generic array object in Java?

I'm looking for a way to store different data types in one fixed length collection so I can set/get elements by index. What's the best way to go about this?
Thanks!
EDIT:
Should this work?
private List t=new ArrayList();
t.set(2,"test");
I get this: java.lang.IndexOutOfBoundsException: Index: 2, Size: 0
Should this work?
private List t=new ArrayList();
t.set(2,"test");
No it shouldn't. A List doesn't automagically grow if you call set with a position that is beyond the end of the list. (See the javadoc.)
If you want to do that kind of thing you have to fill the List with null elements first; e.g.
private List t=new ArrayList();
for (int i = 0; i < LIMIT; i++) {
t.add(null);
}
...
t.set(2,"test");
But I'd also like to reiterate the point that various other answers have made. You should write a class and do this in a type-safe fashion. Stuffing things into an Object[] or List<Object> ... and hoping that you get the indexes and types right ... gives you fragile code. It is bad practice.
You need a Javabean. Create a class which represents the whole picture of all those different properties together. E.g. an User with id, name, gender, dateOfBirth, active, etc.
public class User {
private Long id;
private String name;
private Gender gender;
private Date dateOfBirth;
private Boolean active;
// Add/generate c'tor(s)/getters/setters/equals and other boilerplate.
}
This way you end up with a clear and reuseable abstraction.
User user = new User();
user.setName("John Doe");
user.setGender(Gender.MALE);
// ...
See also:
What is a Javabean?
You can do such a thing with List. It has get/set methods by index. I don't see why fixed length is important here.
You can always encapsulate precisely the behavior you want in a class of your own devising. You can have a backing array to manage it for you, but you'll have to do all the work yourself.
Can't you make an array of Objects? Which means everything except the primitive types (int, char, boolean, etc.); if you want to store them you have to wrap them in their corresponding Object Wrapper classes (Integer, Character, Boolean, etc.) So like:
mult_type[0] = "A String";
mult_type[1] = new Integer(42);
mult_type[2] = new Long(7149994000);
and so on. Although mult_type[i] is an Object by definition, the entry
stored there can be any subclass of Object. When you want to retrieve them,
you can examine them to find out what class they actually belong to. There
are a couple of ways to do this, one is to use the "instanceof" operator
like so:
if (mult_type[i] instanceof Integer) {
Integer anInteger = (Integer)mult_type[i];
int anInt = anInteger.intValue();
}
Notice that you have to "cast" the object to its actual class as you
retrieve it.

Categories

Resources