I have a map I build when called on object that provides caller with variable names as key and getter/setter pair as values. This works as expected. My issue is that I build it every time I call for it, and I am wondering if there is a way to declare it static and supply only the object I want to invoke it on, that way I'm not building the map every time since getters and setters don't change at runtime.
What I have:
package main;
import org.javatuples.Pair;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public interface MapPackHelperI
{
public Map<String, Pair<Supplier, Consumer>> getNameToGetterSetterMap();
}
package main;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import org.javatuples.Pair;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class SomeStruct implements MapPackHelperI
{
private long somelong;
private String somestring;
private List<Float> somelistfloat;
private SomeEnum someenum;
public Map<String, Pair<Supplier, Consumer>> getNameToGetterSetterMap()
{
Map<String, Pair<Supplier, Consumer>> nameToGetterSetterMap = new HashMap<>();
nameToGetterSetterMap.put("somelong", Pair.with( this::getSomelong, (Consumer<Long>)this::setSomelong));
nameToGetterSetterMap.put("somestring", Pair.with( this::getSomestring, (Consumer<String>)this::setSomestring));
nameToGetterSetterMap.put("somelistfloat", Pair.with( this::getSomelistfloat, (Consumer<List<Float>>)this::setSomelistfloat));
nameToGetterSetterMap.put("someenum", Pair.with( this::getSomeenum, (Consumer<SomeEnum>)this::setSomeenum));
return nameToGetterSetterMap;
}
public long getSomelong() {
return this.somelong;
}
public void setSomelong(long somelong) {
this.somelong = somelong;
}
public String getSomestring() {
return this.somestring;
}
public void setSomestring(String somestring) {
this.somestring = somestring;
}
public List<Float> getSomelistfloat() {
return this.somelistfloat;
}
public void setSomelistfloat(List<Float> somelistfloat) {
this.somelistfloat = somelistfloat;
}
public SomeEnum getSomeenum() {
return this.someenum;
}
public void setSomeenum(SomeEnum someenum) {
this.someenum = someenum;
}
// ... hashcode, toString, and equals, not relevant for the example
}
This allows me to do from elsewhere:
public static String serialize(MapPackHelperI objectToSerialize)
{
Map<String, Pair<Supplier, Consumer>> nameToGetterSetterMap = objectToSerialize.getNameToGetterSetterMap();
for(Entry<String, Pair<Supplier, Consumer>> current : nameToGetterSetterMap.entrySet())
{
String name = current.getKey();
Supplier getter = current.getValue().getValue0();
//code that serializes into string with name and getter regardless of the MapPackHelperI I pass in
}
// return the string representation of the object. I have another method that uses the same map to go the other way with the setter.
}
Like I said, this works, but I'm instantiating and filling the map each time I call on it.
Is there a way to have SomeStruct
have a public static Map<String, Pair<Supplier, Consumer>> nameToGetterSetterMap = new HashMap<>();
(or some equivalent) such that public Map<String, Pair<Supplier, Consumer>> getNameToGetterSetterMap()
takes as parameter an instantiated SomeStruct
and just applies the calls to that particular object.
I tried doing a static map and filling it with SomeStruct::getSomelong
and so on, but the compiler said I can't do that.
The answer seems so obvious that I must be missing something: Cache the newly constructed map as a private member field.
public class SomeStruct implements MapPackHelperI
{
…
private Map<String, Pair<Supplier, Consumer>> map =
Map.of(
"somelong", Pair.with( this::getSomelong, (Consumer<Long>)this::setSomelong) ,
"somestring", Pair.with( this::getSomestring, (Consumer<String>)this::setSomestring) ,
"somelistfloat", Pair.with( this::getSomelistfloat, (Consumer<List<Float>>)this::setSomelistfloat) ,
"someenum", Pair.with( this::getSomeenum, (Consumer<SomeEnum>)this::setSomeenum)
) ;
public Map<String, Pair<Supplier, Consumer>> getNameToGetterSetterMap()
{
return this.map ;
}
…
Be aware that the Map
implementation returned by Map.of
is shallowly unmodifiable.
You should be able to make that map
member variable static
. But unless you know for certain you are doing a zillion instantiations of SomeStruct
, I would consider that a micro-optimization that is not worth the bother.
private static Map<String, Pair<Supplier, Consumer>> map = …
By the way, that JavaTuples library looks nifty. But with records in Java 16+, you might consider writing your own little Pair
class.