Issue
I have 2 classes and contains the below property languageMap
class Person {
Map<String, String> languageMap;
}
class Employee {
Map<String, String> languageMap;
}
There are two methods addressMap(List<Person> persons)
and employeeMap(List<Employee> employee)
it calls Function interface,
public Map<String, String addressMap(List<Person> persons){
Function<Collection<Person>,
Map<String, String>> personFunc = CommonUtils::buildPersonMap;
return personFunc.apply(persons);
}
public Map<String, String employeeMap(List<Employee> employee){
Function<Collection<Employee>,
Map<String, String>> addressFunc = CommonUtils::buildEmployeeMap;
return addressFunc.apply(employee);
}
private static Map<String, String> buildPersonMap(Collection<Person> personItem) {
return personItem.stream()
.filter(element -> element.getLanguageMap() != null)
.flatMap(element -> element.getLanguageMap()
.entrySet()
.stream())
.filter(map -> map.getKey() != null && map.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
}
private static Map<String, String> buildEmployeeMap(Collection<Employee> employeeItem) {
return employeeItem.stream()
.filter(element -> element.getLanguageMap() != null)
.flatMap(element -> element.getLanguageMap()
.entrySet()
.stream())
.filter(map -> map.getKey() != null && map.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
}
I wanted to make the 2 buildXXX()
methods to be common, and tried to use Generics as below,
private static Map<String, String> buildMap(Collection<?> input) {
return input.stream()
.filter(element -> element.getLanguageMap() != null). // ERROR
.flatMap(element -> element.getLanguageMap().entrySet().stream()) // ERROR
.filter(map -> map.getKey() != null && map.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a));
}
any Generics or Stream technique to overcome the issue?
Solution
You can make the caller send in a getter for each type, and have your method implemented in this way:
private static <T> Map<String, String> buildMap(Collection<T> input,
Function<T, Map<String, String>> languageMapGetter) {
return input.stream()
.map(languageMapGetter) //you can also call it yourself
.filter(Objects::nonNull)
.flatMap(element -> element.entrySet().stream())
.filter(map -> map.getKey() != null && map.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue, (a, b) -> a));
}
Which will make your type-specific methods look like this:
public Map<String, String> addressMap(List<Person> persons) {
return CommonUtils.buildMap(persons, Person::getLanguageMap);
}
public Map<String, String> employeeMap(List<Employee> employee) {
return CommonUtils.buildMap(employee, Employee::getLanguageMap);
}
Answered By - ernest_k
Answer Checked By - David Marino (JavaFixing Volunteer)