Is it possible to combine these methods? (Java Generics)

A.S. :

I'm working on a homework assignment for University which does not allow me to change the properties of the classes. I came up with the following code for a search method, but I can't help but notice the duplicate code. I am required to build two search methods. One that searches an ArrayList<Person> and one that searches an ArrayList<Module. Both Person and Module have a String name property.

public static <T extends Person> ArrayList<T> findPerson(List<T> list, String query) {
    ArrayList<T> matching = new ArrayList<>();
    list.forEach(s -> {
        if (s.name.contains(query)) matching.add(s);
    });
    return matching;
}

public static <T extends Module> ArrayList<T> findModule(List<T> list, String query) {
    ArrayList<T> matching = new ArrayList<>();
    list.forEach(s -> {
        if (s.name.contains(query)) matching.add(s);
    });
    return matching;
}

Is it possible to combine these methods without changing the class structure? I tried something along these lines but it still doesn't seem to work: (different type argument in method signature)

public static <T extends Person, Module> ArrayList<T> findModule(List<T> list, String query) {
    ArrayList<T> matching = new ArrayList<>();
    list.forEach(s -> {
        if (s.name.contains(query)) matching.add(s);
    });
    return matching;
}

Edit: Here are the classes:

public abstract class Person extends TableItem {

public String name, famName, street, zip, city;
public String[] data = new String[7];

...
}

public class Module extends TableItem {

private Manager manager;
public String[] data = new String[5];
public String name, nr, profID, semester, part;
public ArrayList<String> participants;

...
}

public abstract class TableItem {

public abstract String getString();
public abstract void updateData();
}
jbx :

Ideally you make both your classes implement the same interface, like NamedItem which would have a function getName(), it would be much simpler, because you make your function take List<? extends NamedItem>. If this is not possible, you will have to provide a Function to determine what String property to match.

public static <T> List<T> find(List<T> list, String query, Function<T, String> keyExtractor) {
    return list
        .stream()
        .filter(s -> keyExtractor.apply(s).contains(query))
        .collect(Collectors.toList());
}

Then you can use it like:

List<Person> matchingPersons = find(allPersons, query1, Person::getName);
List<Module> matchingModules = find(allModules, query1, Module::getName);

You can use it with any property, not just name. You just pass the function that extracts the String you want to match as the 3rd parameter.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=90939&siteId=1
Recommended