Could I advise you in trying to make it a little bit more functional?
For your code consider the following helper, this one will make use of function as a first class citizen concept and make some High Order Functions:
private <T, V> Function<Supplier<T>, Supplier<T>> helper(Supplier<V> v,
BiConsumer<T, V> bc) {
return (Supplier<T> r) -> {
bc.accept(r.get(), v.get());
return r;
};
}
This helper function expects a Supplier of some value kind of value and a BiConsumer that will be your setter function. The returns is a function of Suppliers of the same class you are working with.
With that we can make something like a pipe operator of functional languages. Their premises is that the data should processed in a pipeline operation.
List<Class1> data1 = Arrays.asList(new Class1(), new Class1());
List<Class2> data2 = Arrays.asList(new Class2(), new Class2());
Supplier<Double> random = () -> Math.random();
This will be our data, you have the same array and now a Supplier with the random value you want.
Now lets compose our pipeline with andThem:
data1.stream()//
.forEach(data -> {
helper(random, Class1::setOneNum)//
.andThen(helper(random, Class1::setAnotherNum))//
.andThen(helper(random, Class1::setMoreNum))//
.apply(() -> data);
System.out.println(data.toString());
});
data2.stream()//
.forEach(data -> {
helper(random, Class2::setSomeNum1)//
.andThen(helper(random, Class2::setSomeNum2))//
.apply(() -> data);
System.out.println(data.toString());
});
As you can see the helper function can be chained together with "andThem" method of Function interface. This will make Java execute the helper function and use it's return as the parameter of the next Function.
The data parameter will hole the values of classes and will be changed each chain. As we iterated all objects will
And the result:
- Class1 [oneNum=0,047, anotherNum=0,482, moreNum=0,339]
- Class1 [oneNum=0,131, anotherNum=0,889, moreNum=0,411]
- Class2 [someNum1=0,18, someNum2=0,004]
- Class2 [someNum1=0,497, someNum2=0,702]
I think it is the same result you want. And as you can see you don't need to pass any generics as the Java will understand it well.
The classes that I made for reference:
class Class1 {
double oneNum;
double anotherNum;
double moreNum;
public double getOneNum() {
return oneNum;
}
public void setOneNum(double oneNum) {
this.oneNum = oneNum;
}
public double getAnotherNum() {
return anotherNum;
}
public void setAnotherNum(double anotherNum) {
this.anotherNum = anotherNum;
}
public double getMoreNum() {
return moreNum;
}
public void setMoreNum(double moreNum) {
this.moreNum = moreNum;
}
@Override
public String toString() {
return MessageFormat.format("Class1 [oneNum={0}, anotherNum={1}, moreNum={2}]", oneNum, anotherNum, moreNum);
}
}
class Class2 {
double someNum1;
double someNum2;
public double getSomeNum1() {
return someNum1;
}
public void setSomeNum1(double someNum1) {
this.someNum1 = someNum1;
}
public double getSomeNum2() {
return someNum2;
}
public void setSomeNum2(double someNum2) {
this.someNum2 = someNum2;
}
@Override
public String toString() {
return MessageFormat.format("Class2 [someNum1={0}, someNum2={1}]", someNum1, someNum2);
}
}