Reputation: 101
I am learning Java 8 Functional Interface and was trying out some examples. I am trying to create a method which will accept Generic List as one argument and a String data filter argument as another. Below code is working as expected, but when I am trying to convert Predicate into Lambda Expression, then I am struggling.
@SuppressWarnings("unchecked")
public static <T> List<T> filter_and_find_only_selected_Data1(List<T> genericList, String dataFilter){
Stream<List<T>> list = genericList.stream().map(eachListObj-> {
if(eachListObj instanceof Employee){
return genericList.stream().filter((Predicate<? super T>) new Predicate<Employee>() {
public boolean test(Employee eachEmpObj) {
return eachEmpObj.getEmpDept().equalsIgnoreCase(dataFilter);
}
}).collect(Collectors.toList());
}else if(eachListObj instanceof Customer){
return genericList.stream().filter((Predicate<? super T>) new Predicate<Customer>(){
public boolean test(Customer eachCust) {
return !eachCust.getCustomerName().equalsIgnoreCase(dataFilter);
}
}).collect(Collectors.toList());
}
return null;
});
return list.findAny().get();
}
Is there any way, I can convert the Predicate into Lambda as well as if there a way, I can convert if-else-if into Ternary Operator. Like: (if condition)?return Value:(else-if condition):return value:null;
Upvotes: 2
Views: 850
Reputation: 298233
I think, you actually want something like this:
public static <T> List<T> filter_and_find_only_selected_Data(
List<T> list, Function<? super T, String> stringProperty, String filterValue) {
return list.stream()
.filter(t -> filterValue.equalsIgnoreCase(stringProperty.apply(t)))
.collect(Collectors.toList());
}
Then, the caller can use
List<Employee> source = …;
List<Employee> filtered
= filter_and_find_only_selected_Data(source, Employee::getEmpDept, "value");
or
List<Customer> source = …;
List<Customer> filtered
= filter_and_find_only_selected_Data(source, Customer::getCustomerName, "Bob");
or
List<File> source = Arrays.asList(new File("foo", "bar"), new File("foo", "test"),
new File("xyz"), new File("TEST"), new File("abc", "bar"), new File("bla", "Test"));
List<File> filtered = filter_and_find_only_selected_Data(source, File::getName, "test");
to demonstrate the flexibility of a truly generic method.
Upvotes: 3
Reputation: 44398
The generics doesn't help you much here since Customer
and Employee
seem not mutually compatible. As long as you want to use a generic type <T>
, you have to assure that this type is consistent across all the method scope execution. All you can do is using the explicit cast.
I'd start with a static Map
extracting a mapping function based on the incoming Class<?>
. The Function<Object, String>
results in String
as long as you wish to compare these with dataFilter
:
static Map<Class<?>, Function<Object, String>> exctractionMap() {
Map<Class<?>, Function<Object, String>> map = new HashMap<>();
map.put(Customer.class, item -> Customer.class.cast(item).getCustomerName());
map.put(Employee.class, item -> Employee.class.cast(item).getEmpDept());
return map;
}
Putting this static map aside for a while, I think your whole stream might be simplified anyway. This should work together:
static List<String> findSelectedData(List<?> genericList, String dataFilter) {
return genericList.stream() // Stream<Object>
.map(item -> exctractionMap() // Stream<String> using the function
.get(item.getClass()) // ... get through Class<Object>
.apply(item)) // ... applied Function<Object,String>
.filter(s-> s.equalsIgnoreCase(dataFilter)) // Stream<String> equal to dataFilter
.collect(Collectors.toList()); // List<String>
}
A note: Please, respect the Java conventions and name the method filterAndFindOnlySelectedData1
.
Upvotes: 0
Reputation: 1420
Why not put all in the filter? try this
return genericList.stream().filter(item ->
(item instanceof Customer && ((Customer) item).getCustomerName().equalsIgnoreCase(dataFilter)
|| (item instanceof Employee && ((Employee) item).getEmpDept().equalsIgnoreCase(dataFilter))))
.collect(Collectors.toList());
or extract a function for this filter
public boolean isAllow(T item, String dataFilter) {
return (item instanceof Customer && ((Customer) item).getCustomerName().equalsIgnoreCase(dataFilter))
|| (item instanceof Employee && ((Employee) item).getEmpDept().equalsIgnoreCase(dataFilter)))
}
//then use it in filter
return genericList.stream().filter(item -> isAllow(item, dataFilter)
.collect(Collectors.toList());
Hope it helps
Upvotes: 0