I am trying to pass a selected "get"-method of class A to a method in class B. I have checked out Java Pass Method as Parameter, but I was not able to adopt the interface approach to my problem in a reasonable way. I would prefer to not use java 8 (lambdas) and if possible avoid reflection as well. My feeling is, that I am looking at my problem the wrong way. Here is the specific simplified example of what I am trying to accomplish:
I have a class containing some fields and get-methods:
public class DataStore {
private float a;
private float b;
private float c;
public float getA() {
return a;
}
public float getB() {
return b;
}
public float getC() {
return c;
}
}
Next I have my main class instantiating DataStore
as Values of a Map and then accessing specific fields of DataStore like:
public class App {
public static void main(String[] args) {
// declare TreeMap using DataStore class as value
Map<Integer, DataStore> dataMap = new TreeMap<Integer, DataStore>();
// populate Map with example data
dataMap.put(2, new DataStore(1f,2f,3f));
dataMap.put(10, new DataStore(3f,4f,5f));
dataMap.put(4, new DataStore(6f,7f,8f));
// work with specific fields in DataStore, e.g. assign to array
float[] aArray = getValuesAsArray(dataMap, DataStore.getA());
float[] bArray = getValuesAsArray(dataMap, DataStore.getB());
float[] cArray = getValuesAsArray(dataMap, DataStore.getC());
}
/**
* Assign specific field of DataStore from Map to Array
* @param dataMap
* @param getVar - reference for specified getter method
* @return
*/
private static float[] getValuesAsArray(Map<Integer, DataStore> dataMap, MethodReference getVar()) {
int i = 0;
int nMap = dataMap.size();
float[] fArray = new float[nMap];
for (Map.Entry<Integer, DataStore> entry : dataMap.entrySet()) {
DataStore ds = entry.getValue();
fArray[i] = ds.getVar();
i++;
}
return fArray;
}
}
Clearly this wont work, as I have to figure out how to pass my selected get method into getValuesAsArray()
.
Somehow, I guess, my approach may be wrong. So I am open for suggestions.
Your getX()
methods can be seen as a Function that accepts a DataStore instance and returns a float.
In Java 8 you can represent them with method references :
float[] aArray = getValuesAsArray(dataMap, DataStore::getA);
float[] bArray = getValuesAsArray(dataMap, DataStore::getB);
float[] cArray = getValuesAsArray(dataMap, DataStore::getC);
Then your getValuesAsArray
will accept a Function<DataStore,Float>
parameter and execute the function :
private static float[] getValuesAsArray(Map<Integer, DataStore> dataMap, Function<DataStore,Float> func) {
int i = 0;
int nMap = dataMap.size();
float[] fArray = new float[nMap];
for (Map.Entry<Integer, DataStore> entry : dataMap.entrySet()) {
DataStore ds = entry.getValue();
fArray[i] = func.apply(ds);
i++;
}
return fArray;
}
Without using Java 8, you can define your own interface that contains a method that accepts a DataStore
instance and returns a float
. Then, instead of using Java 8 method references, you would have to pass to your getValuesAsArray
method an implementation of that interface (you could use an anonymous class instance implementing the interface) which calls one of the getX()
methods.
For example :
public interface ValueGetter
{
public float get (DataStore source);
}
float[] aArray = getValuesAsArray(dataMap, new ValueGetter() {public float get (DataStore source) {return source.getA();}});
float[] bArray = getValuesAsArray(dataMap, new ValueGetter() {public float get (DataStore source) {return source.getB();}});
float[] cArray = getValuesAsArray(dataMap, new ValueGetter() {public float get (DataStore source) {return source.getC();}});
And
private static float[] getValuesAsArray(Map<Integer, DataStore> dataMap, ValueGetter func) {
int i = 0;
int nMap = dataMap.size();
float[] fArray = new float[nMap];
for (Map.Entry<Integer, DataStore> entry : dataMap.entrySet()) {
DataStore ds = entry.getValue();
fArray[i] = func.get(ds);
i++;
}
return fArray;
}
Awhile ago I used java.util.concurrent.Callable but it doesn't seem to work out, thanks to @Eran.
Instead, you can use Java 8's java.util.function.Function
, like so (without the lambdas):
public static void main(String[] args) {
//...
getValuesAsArray(dataMap, new Function<DataStore,Float>(){ public Float apply(DataStore input) { return input.getA(); }});
getValuesAsArray(dataMap, new Function<DataStore,Float>(){ public Float apply(DataStore input) { return input.getB(); }});
getValuesAsArray(dataMap, new Function<DataStore,Float>(){ public Float apply(DataStore input) { return input.getC(); }});
}
private static float[] getValuesAsArray(Map<Integer, DataStore> dataMap, Function<DataStore, Float> function) {
int i = 0;
int nMap = dataMap.size();
float[] fArray = new float[nMap];
for (Map.Entry<Integer, DataStore> entry : dataMap.entrySet()) {
DataStore ds = entry.getValue();
fArray[i] = function.apply(ds);
i++;
}
return fArray;
}
There is a workaround: Scala java apis.
I use Apache Spark and scala offers a series of Anonymous Functions (Function, Function2) which are available since Java 1.5, if I'm not mistaken (although I use it with Java 1.7).
Here is an answer talking about this. Because otherwise the "Function" class is available only from Java 1.8
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With