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?
CodePudding user response:
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));
}
}
}
CodePudding user response:
You can simplify this code using generics.
Here is one of your if
blocks:
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));
}
}
}
A few things stand out:
- It uses
Employee
- this is a "type"; generics can help here. - It uses
Employee.class
- this is ajava.lang.Class
; generics cannot help here, since types and classes are not the same thing.
Below is a new function which:
- Uses generics to define
<T>
– this is the part right beforevoid
; so,T
is not the return type, but the type of the method. It's screwy syntax, but it's correct and it works. - Requires a
Class
parameter "cls" - this is where the caller would pass in something likeEmployee.class
. Remember, classes are not types – we can't get this class info fromT
, that's not how it works.
private static <T> void extracted(Map<String, List<?>> mvm, Class<?> data, Class<?> cls) {
if (data.isAssignableFrom(cls)) {
for (T rd : (List<T>) mvm.get(0).get(1)) {
// do things
}
}
}
You can then call that new function like this, specifying a type in the function call – GenericsExample.<Employee>extracted(...)
– as well as the class to use (Employee.class, Department.class). I filled in a few other things (dummy definition for mvm
and data
) in order to make the code valid.
public class GenericsExample {
public static void main(String[] args) {
Map<String, List<?>> mvm = new HashMap<>();
Class<?> data = new Object().getClass();
GenericsExample.<Employee>extracted(mvm, data, Employee.class);
GenericsExample.<Department>extracted(mvm, data, Department.class);
}
}
UPDATE: I've thought a bit more about the problem you're solving and the solution I provided. It feels like if you were to take a step back, there is probably a better overall solution than specifying a type T
and a class. But, with the problem stated as it is, I'll leave this solution as it is, too.