javajava-8instance-methods

How to choose pass instance method to use to a method in Java


I have a method that sorts a List by different criteria and returns the name (an instance variable) of the one with maximum value. In case more than one instance is having the maximum, all of their names should be concatenated.

Let's say I have Class A as follows.

Class A {
    ...
    String getName(){...}
    int getValue1() {...}
    int getValue2() {...}
    ...
    int getValueN() {...}
    ...
}

I have a List<A> listToSort. I would normally sort this list as listToSort.sort(Comparator.comparing(A::getValue1)) or listToSort.sort(Comparator.comparing(A::getValue2)), so on and so forth. Then get the ones sharing the maximum value.

In a method I believe this should be done as:

String getMaxString (Comparator c) {
    listToSort.sort(c);
    ...
}

and send Comparator.comparing(A.getValueX) as parameter to call it with different methods. (X here indicates an arbitrary number for the getValue function).

However, I need to also return other instances sharing the same values I will need to pass the Class methods to my method and call on instances as:

String getMaxString (Comparator c) {
    listToSort.sort(c);

    int maxValue = listToSort.get(listToSort.size() - 1).getValueX();
    String maxString = listToSort.get(listToSort.size() - 1).getName();

    for (int i = listToSort.size() - 2; i >= 0; i--) {
        if (listToSort.get(i).getValueX()() == maxValue) {
            maxString += ", " + listToSort.get(i).getName();
        }
    }
    return maxString;
}

How would I pass this method to call on instances here? Or do I need to consider another way?

Edit:

I have a list of Courses as List<Course> mylist where a course can be simplified as:

Class Course {
    private String name;
    private int capacity;
    private int students;
    
    ...
    //bunch of getters.
}

My task is to return Strings for the course(es) with maximum capacity, the course(es) with maximum registered students, the course(es) with most difficulty, the maximum filled percentage, the course(es) with the maximum number of TAs etc...

Edit 2: As requested in the comment section.

List of

Course a (name "a", capacity 10, students 5)
Course b (name "b", capacity 20, students 5)
Course c (name "c", capacity 30, students 0)

Sorting based on capacity should return "c"

Sorting based on students should return "a b"


Solution

  • You can pass the getter method and create the Comparator in getMaxString:

    import java.util.ArrayList;
    import java.util.Comparator;
    import java.util.List;
    import java.util.function.Function;
    
    public class Foo {
        static class AClass {
            private final String name;
            private final int value1;
            private final int value2;
    
            String getName() { return name; }
            int getValue1() { return value1; }
            int getValue2() { return value2; }
    
            public AClass(String name, int value1, int value2) {
                this.name = name;
                this.value1 = value1;
                this.value2 = value2;
            }
        }
    
        static String getMaxString(Function<AClass,Integer> f, List<AClass> listToSort) {
            listToSort.sort(Comparator.comparing(f));
            int maxValue = f.apply(listToSort.get(listToSort.size() - 1));
            String maxString = listToSort.get(listToSort.size() - 1).getName();
    
            for (int i = listToSort.size() - 2; i >= 0; i--) {
                if (f.apply(listToSort.get(i)) == maxValue) {
                    maxString += ", " + listToSort.get(i).getName();
                }
            }
            return maxString;
        }
    
        public static void main(String[] args) {
            List<AClass> list = new ArrayList<>();
            list.add(new AClass("a", 1,2));
            list.add(new AClass("b", 1,2));
            list.add(new AClass("c", 2,1));
            list.add(new AClass("d", 2,1));
            System.out.println(getMaxString(AClass::getValue1, list));
            System.out.println(getMaxString(AClass::getValue2, list));
        }
    }
    

    As Tim Moore suggested above, it isn't necessary to sort the list (which has cost O(n*log n)), we can traverse it twice:

        static String getMaxString2(ToIntFunction<AClass> f, List<AClass> listToSort) {
            int maxValue = listToSort.stream().mapToInt(f).max().orElseThrow();
            return listToSort.stream()
              .filter(a -> maxValue == f.applyAsInt(a))
              .map(AClass::getName)
              .collect(Collectors.joining(", "));
        }
    

    Note that you should test your code with an empty list.