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

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());

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())

How to set field value of CompletableFuture object with second ComputableFuture object

I have a method like:
public CompletableFuture<List<Employee>> handleFutures(CompletableFuture<Factory> factoryCompletableFuture, CompletableFuture<Task> taskCompletableFuture)
throws ExecutionException, InterruptedException {
//logic
}
I want to use CompletableFuture<Task> taskCompletableFuture to set the value of a field task in the CompletableFuture<Factory> factoryCompletableFuture object.
Task class looks like:
public enum Task {
MECHANIC,
ENGINEER
}
Employee class looks like:
public class Employee {
private Task task;
}
Factory class looks like:
public class Factory{
private Optional<List<Employee>> employees;
}
I have a stream like:
Task task = taskCompletableFuture.get();
List<Employee> collect = factoryCompletableFuture.get().getEmployees().stream()
.flatMap(Collection::stream)
.peek(empl -> empl.setTask(task))
.map(CompletableFuture::completedFuture)
.map(CompletableFuture::join)
.collect(toList());
which return List of Employee.
All I want to achieve is wrapping in a gentle way above stream with CompletableFuture to get a result as CompletableFuture<List<Employee>> and call a method logic like:
return factoryCompletableFuture.thenApply(do logic here which will set value and return CompletableFuture).
By the way, I know that Optional with a list is not a good practice but I cannot change this. Peek for setter usage is either not the best option but this maneuver doesn't need an additional object to repack the changed object with eventual forEach usage.
I will be grateful for a suggestion on how to reach a desirable goal.
You simply need to use thenCombine():
public CompletableFuture<List<Employee>> handleFutures(
CompletableFuture<Factory> factoryCompletableFuture,
CompletableFuture<Task> taskCompletableFuture) {
return factoryCompletableFuture.thenCombine(taskCompletableFuture,
(factory, task) -> factory.getEmployees().stream()
.flatMap(Collection::stream)
.peek(empl -> empl.setTask(task))
.collect(toList()));
}

How to set a specific return type to a method in Java

So I have a class called Person
I can easily do something like
Person getPerson(){ return new Person(); }
But instead of using the 'Person' I want to declare my own class as a return type
Class<?> personClass = Class.forName("Person");
personClass getPerson() { return new Person(); }
Is this possible?
Your design is almost certainly wrong if you want to implement this, but yes, it's possible.
Object getThing(String className) throws Exception
{
return Class.forName(className).getConstructor().newInstance();
}
You'll have to cast the result.
If you want Person class object (I mean, Class<Person>), you can just use Person.class or personInstance.getClass().
Also, if you want a custom method that will return it, then you can use:
public Class<Person> getPersonClass() {
return Person.class;
}
But it is almost pointless, because you can just call Person.class. Beware, also, that Person.class is evaluated in compile time, and Class.forName("...") - in runtime.

for each loop of objects of specific instances in 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
});

Anything wrong with instanceof checks here?

With the introduction of generics, I am reluctant to perform instanceof or casting as much as possible. But I don't see a way around it in this scenario:
for (CacheableObject<ICacheable> cacheableObject : cacheableObjects) {
ICacheable iCacheable = cacheableObject.getObject();
if (iCacheable instanceof MyObject) {
MyObject myObject = (MyObject) iCacheable;
myObjects.put(myObject.getKey(), myObject);
} else if (iCacheable instanceof OtherObject) {
OtherObject otherObject = (OtherObject) iCacheable;
otherObjects.put(otherObject.getKey(), otherObject);
}
}
In the above code, I know that my ICacheables should only ever be instances of MyObject, or OtherObject, and depending on this I want to put them into 2 separate maps and then perform some processing further down.
I'd be interested if there is another way to do this without my instanceof check.
Thanks
You could use double invocation. No promises it's a better solution, but it's an alternative.
Code Example
import java.util.HashMap;
public class Example {
public static void main(String[] argv) {
Example ex = new Example();
ICacheable[] cacheableObjects = new ICacheable[]{new MyObject(), new OtherObject()};
for (ICacheable iCacheable : cacheableObjects) {
// depending on whether the object is a MyObject or an OtherObject,
// the .put(Example) method will double dispatch to either
// the put(MyObject) or put(OtherObject) method, below
iCacheable.put(ex);
}
System.out.println("myObjects: "+ex.myObjects.size());
System.out.println("otherObjects: "+ex.otherObjects.size());
}
private HashMap<String, MyObject> myObjects = new HashMap<String, MyObject>();
private HashMap<String, OtherObject> otherObjects = new HashMap<String, OtherObject>();
public Example() {
}
public void put(MyObject myObject) {
myObjects.put(myObject.getKey(), myObject);
}
public void put(OtherObject otherObject) {
otherObjects.put(otherObject.getKey(), otherObject);
}
}
interface ICacheable {
public String getKey();
public void put(Example ex);
}
class MyObject implements ICacheable {
public String getKey() {
return "MyObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
class OtherObject implements ICacheable {
public String getKey() {
return "OtherObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
The idea here is that - instead of casting or using instanceof - you call the iCacheable object's .put(...) method which passes itself back to the Example object's overloaded methods. Which method is called depends on the type of that object.
See also the Visitor pattern. My code example smells because the ICacheable.put(...) method is incohesive - but using the interfaces defined in the Visitor pattern can clean up that smell.
Why can't I just call this.put(iCacheable) from the Example class?
In Java, overriding is always bound at runtime, but overloading is a little more complicated: dynamic dispatching means that the implementation of a method will be chosen at runtime, but the method's signature is nonetheless determined at compile time. (Check out the Java Language Specification, Chapter 8.4.9 for more info, and also check out the puzzler "Making a Hash of It" on page 137 of the book Java Puzzlers.)
Is there no way to combine the cached objects in each map into one map? Their keys could keep them separated so you could store them in one map. If you can't do that then you could have a
Map<Class,Map<Key,ICacheable>>
then do this:
Map<Class,Map<Key,ICacheable>> cache = ...;
public void cache( ICacheable cacheable ) {
if( cache.containsKey( cacheable.getClass() ) {
cache.put( cacheable.getClass(), new Map<Key,ICacheable>() );
}
cache.get(cacheable.getClass()).put( cacheable.getKey(), cacheable );
}
You can do the following:
Add a method to your ICachableInterface interface that will handle placing the object into one of two Maps, given as arguments to the method.
Implement this method in each of your two implementing classes, having each class decide which Map to put itself in.
Remove the instanceof checks in your for loop, and replace the put method with a call to the new method defined in step 1.
This is not a good design, however, because if you ever have another class that implements this interface, and a third map, then you'll need to pass another Map to your new method.

Categories

Resources