Java generics method to filter and find first element in list

Viewed 968
private Feature findFeature(String name, List<Feature> list) {
    for (Feature item : list) {
        if (item.getName().equals(name)) {
            return  item;
        }
    }
    return null;
}

I have 10 other methods like this. Same signature, same logic. Only different is that List parameter is using different objects, e.g. List<Data> list, or List<Option> list, etc. All objects has a getName() method in it. I want to create a generic method and remove all others.

If I use something like this,

private <T> T findInList(String name, List<T> list) {

I don't have access the getName() method. What is the easiest way to create this method? Is reflection api the only option?

EDIT:

I found the mistake I did. It is working just fine like this:

for (FeatureEntity entity : data.getFeatures()) {
    Predicate<Feature> filter = f -> f.getName().equalsIgnoreCase(entity.getName());
    if (entity.getFeatureId() != null && findInList(featureList, filter) == null) {
        FeatureEntity n = new FeatureEntity();
        n.setId(entity.getId());
        // ...
    }
}
3 Answers

You can create generic method that takes generic list with Predicate to get the first matching item after filtering

private <T> T findFeature(List<T> list, Predicate<T> predicate) {
    return list.stream().filter(predicate).findFirst().orElse(null);
}

And then create Predicate with required type and call that method

Predicate< Feature > filter = f->f.getName().equalsIgnoreCase(name);
findFeature(list,filter);

On another side, you can also return Optional<T> instead of null when no element is found:

private <T> Optional<T> findFeature(List<T> list, Predicate<T> predicate) {
    return list.stream().filter(predicate).findFirst();
}

You could create a common Named interface, like

public interface Named {
    String getName();
}

Then use a wildcard to specify that the method requires that Named interface.

private <T extends Named> T findInList(String name, List<T> list)

Then you can use getName. Of course, you need to modify the classes you wish to use to implements Named (but you mentioned they all already have getName() methods).

first, you need an Inferface:

public interface HasName {
    String getName();
}

then, your Feature class has to implement it:

public class Feature implements HasName {

After you add the implements to your class name, you need to implement the getName() method (let your IDE help you with this)

then go as follows:

private <T extends HasName> findFeature(String name, List<T> list) {
    // Do your logic, getName will be availible here.
}
Related