Reputation: 11
my problem is duplicit code. I have 4 methods like below but one is for Name, other for Login, etc. So the only thing that changes are getters (p.getName(), p.getLogin()...).
private Set<Person> filterByName(Set<String> values, Set<Person> peeps){
Set<Person> filtered = new HashSet<>();
for (Person p : peeps){
if(isIn(p.getName(), values)){
filtered.add(p);
}
}
return filtered;
}
I call these methods in switch:
switch(var){
case NAME:
filtered = filterByName(arg1, arg2);
case ...
How can I do this without implementing a method for each case
block?
My idea is to somehow tell the method to use the right getter in case
blocks and therefore have only one method for all filtering, e.g.
private Set<Person> universalFilter(Set<String> values, Set<Person> peeps) {
Set<Person> filtered = new HashSet<>();
for (Person p : peeps){
if(isIn(***SOMETHING CLEVER***, values)){
filtered.add(p);
}
}
return filtered;
}
Upvotes: 1
Views: 109
Reputation: 17524
You could pass another String parameter, which would be the variable on which you want to filter ("Name", "Login"...)
Then with reflection, you could find and call the relevant getter method :
Method method = Person.class.getMethod("get"+ filter, null);
String returnValue = (String)(method.invoke(p, null));
if(isIn(returnValue , values))
...
Upvotes: 0
Reputation: 12932
If you are using Java 8, you can use method references to do exactly what you want. The smallest change is to use a Function
object. Your filterByName
method takes an additional argument which maps each Person
object to the property you want to test:
private Set<Person> filter(Function<Person,String> filter, Set<String> values, Set<Person> peeps) {
Set<Person> filtered = new HashSet<>();
for (Person p : peeps){
if(isIn(filter.apply(p), values)){
filtered.add(p);
}
}
return filtered;
}
and then you call the method as follows:
filter(Person::getName, values, peeps);
If you want to allow for more complex filters, you can specify the entire filter as a predicate:
private Set<Person> filter(Predicate<Person,String> filter, Set<Person> peeps) {
Set<Person> filtered = new HashSet<>();
for (Person p : peeps){
if (filter.test(p)){
filtered.add(p);
}
}
return filtered;
}
which can be called with:
filter(p -> isIn(p.getName(), values), peeps);
In fact, Java 8 provides filtering functionality in the run-time library, either by the removeIf
method:
private Set<Person> filter(Predicate<Person,String> filter, Set<Person> peeps) {
Set<Person> filtered = new HashSet<>();
filtered.removeIf(filter);
return filtered;
}
or by using streams:
private Set<Person> filter(Predicate<Person,String> filter, Set<Person> peeps) {
return peeps.stream().filter(filter).collect(Collectors.toSet());
}
Upvotes: 3
Reputation: 2084
A simple way is to use the switch variable to pass in as an argument to a new method get() on Person.
if(isIn(p.get(var), values)){
Then implement the new method in Person, eg:
public void get(String var) {
if (var.equals("NAME")) return name;
...
}
Upvotes: 1