Reputation: 45
private <Y> void meth(
MyObj ds, MultiValueMap<String, List> mvm, Class<Y> data) {
if(data.isAssignableFrom(Employee.class)) {
for (Employee rd : (List<Employee>) mvm.get(0).get(1)) {
for (String cName : (List<String>) mvm.get(0).get(0)) {
ds.setCellValue((String)rd.getDataElement(cName));
}
}
}
if(data.isAssignableFrom(Department.class)) {
for (Department rd : (List<Department>) mvm.get(0).get(1)) {
for (String cName : (List<String>) mvm.get(0).get(0)) {
ds.setCellValue((String)rd.getDataElement(cName));
}
}
}
//some more similar if conditions as above
}
In above, I have like similar 10 if conditions, how to avoid duplicate code in above? Do I need to use any Java 8 Function classes as parameters to avoid duplicate code (or) have to use any extra generics code?
Upvotes: 2
Views: 295
Reputation: 5754
While generic methods can be applied, they won't solve the actual scenario you're trying to solve for (an earlier edit of this answer was an attempt before I thought through it more).
Taking a step back, this looks like the problem statement ("what" you're solving for, not "how"):
MultiValueMap<String, List> mvm
getDataElement()
As the other answer by Ausgefuchster describes, this can be solved with interfaces. I voted that answer up, but wanted to provide more more detail and examples.
Regardless of concrete class, your map contains lists of things which have getDataElement()
, so make an interface which captures that:
interface HasDataElement {
String getDataElement();
}
For this answer, I made up a few simple classes – A, B, and C – which implement the interface, but otherwise only return a string when getDataElement()
is called. In your code, you would modify Employee, Department, etc. to implement your new interface.
class A implements HasDataElement {
@Override
public String getDataElement() {
return "A";
}
}
class B implements HasDataElement {
@Override
public String getDataElement() {
return "B";
}
}
class C implements HasDataElement {
@Override
public String getDataElement() {
return "C";
}
}
I'm using built-in types, so Map<String, List>
instead of your posted code which uses MultiValueMap<String, List>
. I think this difference is not significant, but pointing it out anyway.
The method signature below specifies that the map isn't just <String, List>
, but further specifies that the list itself must contain things which extend the HasDataElement
interface: List<? extends HasDataElement>
.
Inside the method, the same List<? extends HasDataElement>
type shows up in the first loop.
Once inside, the concrete class of item
isn't relevant – we know it conforms to the HasDataElement
interface, so we can call item.getDataElement()
.
private static void processAllDataElements(Map<String, List<? extends HasDataElement>> map) {
for (List<? extends HasDataElement> list : map.values()) {
for (HasDataElement item : list) {
System.out.println(item.getDataElement());
}
}
}
Here's a simple example, along with output, that creates a few different lists of the various classes A, B, and C. It then creates a map and adds all three lists.
List<A> listOfA = List.of(new A[]{new A()});
List<B> listOfB = List.of(new B[]{new B(), new B()});
List<C> listOfC = List.of(new C[]{new C(), new C(), new C()});
Map<String, List<? extends HasDataElement>> map = new HashMap<>();
map.put("A", listOfA);
map.put("B", listOfB);
map.put("C", listOfC);
processAllDataElements(map);
A
B
B
C
C
C
Upvotes: 2
Reputation: 1178
So it looks like that what you need is inheritance and not generics. In your if condition you always cast and call the same method on the Object. So what you can do is e.g. define an interface looking something like this:
public interface MyInterface {
String getDataElement(String name);
}
And implement it in your Employee, Department and other classes you have.
If the method always does the same you can use default or an abstract class to not always write the same:
public interface MyInterface {
default String getDataElement(String name) {
//do your thing
return value;
}
}
public abstract class MyAbstractClass {
public String getDataElement(String name) {
//do your thing
return value;
}
}
Now you can change your meth
method to this:
private void meth(MyObj ds, MultiValueMap<String, List> mvm) {
List<MyInterface> list = (List<MyInterface>) mvm.get(0).get(1));
for (MyInterface rd : list) {
List<String> cNames = (List<String>) mvm.get(0).get(0);
for (String cName : cNames) {
ds.setCellValue((String) rd.getDataElement(cName));
}
}
}
Upvotes: 4