Общие аргументы метода - Java

У меня есть два почти одинаковых метода, но я стараюсь избегать дублирования кода.

Каждый из них принимает уникальный объект в качестве аргументов и обнаруживает самое высокое значение из него.

Вот пример:

public Integer getHighestIndexValue(List<ObjectA> list) {
    int highestValue;
    List<Integer> indexes = new ArrayList<Integer>();
    for (ObjectA a: list) {
        indexes.add(Integer.parseInt(a.getA()));
    }
    highestValue = Collections.max(indexes);

    return highestValue;

} 

Или:

public Integer getHighestIndexValue(List<ObjectB> list) {
    int highestValue;
    List<Integer> indexes = new ArrayList<Integer>();
    for (ObjectB b: list) {
        indexes.add(Integer.parseInt(b.getB()));
    }
    highestValue = Collections.max(indexes);

    return highestValue;

}  

Как объединить эти два с помощью общих параметров?

Я попытался создать BaseClass, который содержит эти два класса и расширил его в сигнатуре метода. Тем не менее это требует кастинга.

public <T extends BaseClass> Integer getHighestIndexValue(List<T> objectList) {
    int highestValue;
    List<Integer> indexes = new ArrayList<Integer>();

    for (T objects: objectList) {
        indexes.add(Integer.parseInt(objects.getAorB())); ------ this line needs casting
    }
    highestValue = Collections.max(indexes);

    return highestValue;

}

Я использовал параметры Generics до, но не generics.

Есть ли способ решить эту проблему?

Ответ 1

Можно ли getA и getB объединить в один метод интерфейса?

Например:

interface ProvidesIndex {
  Integer getIndex();
}

Теперь вы можете просто вызвать getIndex, а ваша подпись метода будет:

public Integer getHighestIndexValue(List<? extends ProvidesIndex> list) 

В качестве дополнительной заметки, если вы определяете свой интерфейс для расширения Comparable<ProvidesIndex> i.e.:

interface ProvidesIndex extends Comparable<ProvidesIndex>

Затем вы можете использовать Collections.max непосредственно в исходном списке:

List<ProvidesIndex> list = new ArrayList<ProvidesIndex>();
list.add(new ObjectA());
list.add(new ObjectB());
Integer max = Collections.max(list).getIndex();

Ответ 2

Добавление к ответу Рамана:

public Integer getHighestIndexValue(List<? extends CommonInterface> list) {
    int highestValue;
    List<Integer> indexes = new ArrayList<Integer>();

    for (CommonInterface a: list) {
        indexes.add(Integer.parseInt(a. getIndex()));
    }

    highestValue = Collections.max(indexes);

    return highestValue;
}

Ответ 3

Guava имеет элегантное решение:

//general purpose function to get A, can be used in transform(), etc
private static final Function<ObjectA, Integer> GET_A = new Function<>() {
     @Override
     public Integer apply(ObjectA a) {
         return a.getA();
     }
}

Integer highestIndex = Collections.max(Collections2.transform(list, GET_A));

Или, если вам нужен элемент с самым высоким индексом,

ObjectA highest = Ordering.natural().onResultOf(GET_A).max(list);

Затем, чтобы расширить это до ObjectB, вам просто нужно реализовать функцию GET_B.

Возвращаясь к вашему вспомогательному методу (который теперь практически не имеет значения, если у вас есть однострочный):

public <T> Integer getHighestIndex(List<? extends T> list, Function<? super T, Integer> indexPlucker) {
    return Collections.max(Collections2.transform(list, indexPlucker));
}

Ответ 4

Вы можете сделать это в одной команде Java. Вот как Java 5, так и более компактный Java 8:

public static class ObjectA {
    public String getA() { return "1"; /* test */ }
}

public static class ObjectB {
    public String getB() { return "1"; /* test */ }
}

// Java 5+ versions

public static void sampleA7(List<ObjectA> list) {
    int maxValue = Integer.parseInt(Collections.max(list, new Comparator<ObjectA>() {
        @Override
        public int compare(ObjectA a, ObjectA b) {
            return Integer.parseInt(a.getA()) - Integer.parseInt(b.getA());
        }
    }).getA());
}

public static void sampleB7(List<ObjectB> list) {
    int maxValue = Integer.parseInt(Collections.max(list, new Comparator<ObjectB>() {
        @Override
        public int compare(ObjectB a, ObjectB b) {
            return Integer.parseInt(a.getB()) - Integer.parseInt(b.getB());
        }
    }).getB());
}

// Java 8+ versions

public static void sampleA8(List<ObjectA> list) {
    Optional<Integer> maxValue = list.stream().map(a -> Integer.parseInt(a.getA())).max((a, b) -> a - b);
}

public static void sampleB8(List<ObjectB> list) {
    Optional<Integer> maxValue = list.stream().map(a -> Integer.parseInt(a.getB())).max((a, b) -> a - b);
}

Ответ 5

это, вероятно, не очень хорошая идея, если вы хотите сделать этот код общим, использовать ArrayList из целых чисел, чтобы выполнить фактическое сравнение. Что делать, если один из объектов Long, больше вашего максимального числа? Вместо этого ваши объекты должны быть сопоставимы каким-либо образом, поэтому вы можете найти "максимум" (какой максимальный набор строк?)

Итак, я бы попробовал такой подход

import java.util.List;

public abstract class MathMax<E> {
    public abstract boolean isGreaterThan(E x1, E x2);
    public E getHighestIndexValue(List<E> list){
        E highestValue = null;
        for (E a: list) {
            if (isGreaterThan(a,highestValue)){
                highestValue = a;
            }
        }
        return highestValue;
    }
}

и

import java.util.ArrayList;
import java.util.List;

public class MathMaxA extends MathMax<ObjectA> {

    @Override
    public boolean isGreaterThan(ObjectA x1, ObjectA x2) {
        // do your comparison here, careful with null values
        return false;
    }

    public static void main(String[] args) {
        MathMaxA m = new MathMaxA();
        List<ObjectA> list = new ArrayList<ObjectA>();
        System.out.println(m.getHighestIndexValue(list));
    }
}