for each loop of objects of specific instances in Java - java

I'd like to have a for each loop to loop through an array of objects.. but only the objects that are an instance of a specific class. To be more clear of what I mean, I've included the example below...
//Declare a list of employee objects
List<Employee> employees = new ArrayList<Employees>;
//Create some employees...
Employee employee = new Employee();
//The class EmployeeExtender extends and is a child of Employee
EmployeeExtender employeeExtended = new EmployeeExtender();
//Now add all the employees, even the ones of different instances to the list
employees.add(employee);
employees.add(employeeExtended);
Now I would like to introduce a for each loop that loops through the employees list that only loops through employees that are an instance of EmployeeExtender. I could just loop through each one and use an if statement (as shown below) but I would like to know if there was a way without making a seperate list to do this.
//I would like to only loop through employees that are an instance of EmployeeExtender
for(Employee employee : employees){
//I would like to not have this if statement...
if(employee instanceof EmployeeExtender){
//do logic...
}
}
Are my only options creating separate lists, or using the if statement? I'd like to know if there are more options. Thanks.

One option that hasn't been considered is to dispatch the logic to an empty method, that's overridden in the subclass you're interested in. I don't think I'd recommend doing it this way, but you did ask for options other than the straightforward for-each / instanceof way of doing it.
public class Employee {
public void doTheLogic(TheClassYoureCallingFrom caller) {
}
}
public class EmployeeExtended extends Employee {
#Override
public void doTheLogic(TheClassYoureCallingFrom caller) {
// The actual logic goes here.
}
}
public class TheClassYoureCallingFrom {
List<Employee> employees = new ArrayList<Employees>;
public void theMethodYoureCallingFrom() {
for (Employee employee : employees) {
employee.doTheLogic(this);
}
}
}
Of course, if you're not using any of the methods of the calling class, there's no need to pass it as a parameter.

You could use Streams:
employees.stream()
.filter(employee -> employee instanceof EmployeeExtender)
.forEach(employee -> {
//do logic
});

Related

Java: reading objects from file into different derived classes

I have class Employee, and two derived classes Hourly and Salary. Instantiations of those derived classes are placed in the same Array List called employeeList. When I read these objects from file using ois.readObject() how can I ensure the data ends up in the appropriate derived class? Thank you!
Note: I am not familiar with ObjectInputStream, so I am not exactly sure if this dynamic dispatch would work here, but I recommend giving this a try:
You could have your employee interface look like this:
interface Employee {
// Whatever other methods you have defined
void populateFieldsFromObject(Object obj);
}
Then each subclass would implement this method differently:
class HourlyEmployee implements Employee {
// Other methods/fields...
#override
void populateFieldsFromObject(Object obj) {
if (!(obj instanceof HourlyEmployee)) {
throw new IllegalArugmentException("Object not of correct type");
}
HourlyEmployee objEmp = (HourlyEmployee)Object;
this.hourly = objEmp.hourly;
}
}
class SalaryEmployee implements Employee {
// Other methods/fields...
#override
void populateFieldsFromObject(Object obj) {
if (!(obj instanceof SalaryEmployee)) {
throw new IllegalArugmentException("Object not of correct type");
}
SalaryEmployee objEmp = (SalaryEmployee)Object;
this.salary = objEmp.salary;
}
}
Then you can just iterate through your List of employees, and call:
employee.populateFieldsFromObject(ois.readObject());, as Dynamic Dispatch should automatically determine which method to call based on the type of the object.
Let me know if this works.
I assume they are extensions of the Employee class ? If you have an array like this:
List<Employee> emps = ...
then you can do something like:
for (Employee e : emps) { if (e instanceof Hourly) ... }
You still need to check the elements. You can also use filter them like this:
emps.stream().filter(e -> e instanceof Hourly).collect(Collectors.toList())

object values not the same after changes in an arraylists?

I'm having an issue with some pointers from what I can read about java. It always passes parameters as values rather than references. here
I have a project and employee class that should "share" an object but when I create an instance of activity, add it to the project list and then later add it to the employee list of activities it works. But then when I change the worktime for an employee it's only visible via the project instance where i add the worktime from. It's not visible when i then call the activity worktime from the employee object.
Is there a way to "share" an object between classes e.g. pass it by reference like you can in PHP?
When I output the hashcodes of the activity objects in both classes they are also different...
Project class:
public class Project {
private List<Activity> activites = new ArrayList<Activity>();
public List<Activity> getActivities() {
return activites;
}
public void setActivities(Activity activity) {
this.activites.add(activity);
}
}
employee class:
public class Employee {
private List<Activity> activities = new ArrayList<Activity>();
public List<Activity> getActivities() {
return activities;
}
public void setActivity(Activity activity) {
activities.add(activity);
}
}
activity class:
public class Activity {
private String activityName;
private HashMap<Employee,Integer> workTime = new HashMap<Employee,Integer>();
public Activity(String activity) {
this.activityName = activity;
}
public HashMap<Employee, Integer> getWorkTime() {
return workTime;
}
public void setWorkTime(Employee e, Integer t) {
workTime.put(e, t);
}
}
An example of the issue:
public void main(String[] args) {
Activity a = new Activity('task i');
Project p = new Project();
p.setActivities(a);
Employee e = new Employee();
e.setActivity(a);
p.getActivities().get(0).setWorkTime(e,5);
System.out.println(p.getActivities().get(0).getWorkTime()); // 5
System.out.println(e.getActivities().get(0).getWorkTime()); // -> null (would like 5)
}
The problem is here
public void setWorkTime(Employee e, Integer t) {
workTime.put(e, t);
}
You are putting the employee instance in a map. But the Employee class does not override equals and hashCode so every instance of Employee will be a new and unique key.
You need to override equals and hashCode using some field(s) of the Employee class that would constitute equal instances (e.g. Employee name and/or Employee ID).
UPDATE
In recognition of the comments regarding only a single instance of Employee is being used, I concur. Although I believe it is important to do as I suggested it was not the specific problem.
I ran the above code and made main a static entry point and fixed the Activity argument to correctly add a String. The OP originally had the following:
System.out.println(p.getActivities().get(0).getWorkTime()); // 5
System.out.println(e.getActivities().get(0).getWorkTime()); // -> null (would like 5)
The above does not print 5 or null. It prints the default toString of the map.
The Employee instance must must be supplied as the key via get and it will print 5 in both cases.
System.out.println(p.getActivities().get(0).getWorkTime().get(e)); // 5
System.out.println(e.getActivities().get(0).getWorkTime().get(e)); // 5

How to avoid mutating the state of the object inside a stream?

I have code like people.stream.filter(Object::notNull).map(person -> person.updateAge(...))
I would like to avoid calling updateAge() and even remove that method and make me object immutable. How can I achieve that while keeping the stream structure of the code?
If you want to mutate objects then you are misusing map! it is forEach that is for side effects.
people.forEach(person -> person.updateAge(...))
But no I still like to be functional and use immutable objects. In that case you need to make updateAge takes a new age and return a new person object with that very new age.
Person updateAge(int incrementBy) {
... new Person(..., newAge);
}
And then get a stream of new people like this
people.stream.filter(Object::notNull).map(person -> person.updateAge(...))
I dont want to modify that object directly but rather create a new object will all same fields with age field changed. Is that possible
Yes it is possible. You can override method clone() from Object:
#Override
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
Don't forget to implement Cloneable:
public class Person implements Cloneable {
...
Assuming you have updateAge() method like this:
public Person updateAge(int age) {
this.setAge(age);
return this;
}
Then stream chain will looks like:
List<Person> newPeople = people.stream()
.map(Person::clone)
.map(person -> person.updateAge(...))
.collect(toList());

How can I let my different objects in my ArrayList perform the method each class has (salaris())

Let's say you have different employees but each employee class has a salary() method. How can I make these different objects I made and put in an ArrayList use the method salary()?
public void betaalSalarissen(){
for(int counter = 0;werknemers.size()>counter;counter++){
Class objectClass = werknemers.get(counter).getClass();
**objectClass.salaris();** //this won't work, help please!
}
}
public void neemInDienst(Object persoon){ //objects from different classes, different employees
werknemers.add(persoon);
}
There's no reason to try to get the class; just use polymorphism.
public class Employee {
public double salaris() { ... }
}
public class CommissionedEmployee extends Employee {
#Override
public double salaris() { ... }
}
List<Employee> employees = new ArrayList<>();
// add some employees of whatever subtype(s)
for (Employee e : employees) {
e.salaris();
}
the quick solution here is to cast the result from werknemers.get(counter)``to yourEmployee` class (class name just guessed)
((Employee)werknemers.get(counter)).salaris();
but in the long run you should apply a generic parameter to the collection variable and the methods parameter:
private Collection<Employee> werknemers = new ArrayList<>();
public void neemInDienst(Employee persoon){ //objects from different classes, different employees
werknemers.add(persoon);
}
then you can simply iterate over the element without cast just as ChiefTwoPencils suggested.

Linkend List copy constructor

I am having problems with the copy constructor of a Linkend List in Java.
The list I am trying to copy has a size of 3, when I use the copy constructor the list is empty.
When I try this with the clone method everything works great.
I have look a this for a quite a while and I get the feeling it is so obvious. I just
dont see it, here is the code.
public class Employee {
private String name;
private double salary;
public Employee(String name, double salary){
this.name = name;
this.salary = salary;
}
public void setname(String name){
this.name = name;
}
public void setsalary(double salary){
this.salary = salary;
}
public String getname(){
return this.name;
}
public double getsalary(){
return this.salary;
}
}
public class Main {
public static void main(String[] args) {
Employees employees = new Employees();
employees.add(new Employee("Employee1", 2500.00));
employees.add(new Employee("Employee2", 2400.00));
employees.add(new Employee("Employee3", 2000.00));
Employees employeesCopy2 = new Employees(employees);
Employees employeesCopy = (Employees) employees.clone();
System.out.println(employees.size());
System.out.println(employeesCopy2.size());
System.out.println(employeesCopy.size());
}
}
import java.util.LinkedList;
public class Employees extends LinkedList<Employee> {
private static final long serialVersionUID = 1L;
private LinkedList<Employee> employees;
public Employees(){
employees = new LinkedList<Employee>();
}
public Employees(Employees w){
employees = new LinkedList<Employee>(w);
}
public void addWerknemer(Employee w){
employees.add(w);
}
}
EDIT
This is homework, but when I wanted to add the tag is showed that the tag was no longer is use.
I think this:
public class Employees extends LinkedList<Employee> {
private LinkedList<Employee> employees;
will create a world of confusion. You're both extending a list, and within that class you're maintaining a separate list. When you call addWerknemer() you add to the inner list. What happens when you call get() ? Since you've not overridden this, you're calling get() on the base class, and that's a different list!
Without inspecting the rest of your code, I suspect this is a fundamental source of problems.
You have two choices:
Employees extends List
Employees contains a List
I would prefer the second. You can change the underlying collection (e.g. a Set, perhaps a Map for better lookup performance) and not change the exposed interface.
You are extending LinkedList, but also have a LinkedList inside that extension. Initially you use the add method to add Employee instances, so they get added to the Employees list itself, but when you use the copy constructor, you copy those employees to the employees field inside your Employees class.
When you call the size() method, it will use the LinkedList of the Employees object itself, so in the first list it is 3, but on the second it is 0 as now the employees are in the contained list and not in the object itself.
In this case you probably should not extend LinkedList. Or if you do, then don't use a separate field like employees which also contains a LinkedList.
Your confusion comes from the fact, that Employees both is a list and contains a list. When you use
employees.add(new Employee("Employee1", 2500.00));
you add the employee to the outer list. When you use
employees.addWerknemer(new Employee("Employee1", 2500.00));
you add the employee to the inner list. Since you have overwritten the constructor Employees(Employees es), this will not clone the outer list, but only the inner. And since you haven't overwritten clone(), it will clone the outer list, but not the inner. This is rather messy and also most probably not intended by you. I therefore propose one of the following changes:
1. [Preferred] Employees only contains a list and not extends one
Skip the extends LinkedList<Employee> and only work with an internal list. You will have to use your method addWerknemer(Employee emp) to add to your list (or change it's name to add). You will have to implement size and clone as well as other methods that you wish to use. If you want to be really clean about this, you can even make the class implement List or implement Collection or so. This way you can still treat your class as a java.util.Collection. I don't think that this would be neccessary in your case though. Also you would need to implement all of the interfaces methods (there are many). An example implementation would look like this. You still have to implement size, etc.
public class Employees /*implements List<Employees>*/ {
private static final long serialVersionUID = 1L;
private LinkedList<Employee> employees;
public Employees(){
employees = new LinkedList<Employee>();
}
public Employees(Employees w){
employees = new LinkedList<Employee>(w);
}
public void add(Employee w){
employees.add(w);
}
public Employees clone() {
return employees.clone();
}
// add more methods as you need them (like remove, get, size, etc)
}
2. Employees only extends LinkedList and doesn't contain one
Throw away your methods addWerknemer(Employee emp) and the copy constructor Employees(Employees) as well as your internal list. This way you will not overwrite the existing implementations of LinkedList. This approach is more or less useless because you basically just rename LinkedList to Employees and add/change nothing. Therefore I wouldn't recommend this approach.

Categories

Resources