I'm learning Java lambdas for school, and I am stuck for a couple of days now.
I have a list of pumps which I have to sort out on power, last revision, …
I already wrote a Comparator
that's returning a List<Pump>
:
class PowerComparator implements Comparator<Pomp> {
@Override
public int compare(Pump pump1 , Pump pump2) {
return Double.compare(pump1.getPower(), pump2.getPower());
}
}
I have to write one function that's returning a List<Pump>
that can returning a sorted list (power, revision, ...) using a lambda.
The method signature is:
public List<Pump> sortedBy(Function<Pump, Comparable<Pump>> function)
I know that the Function
interface is returning a Comparator
, but I don't know how to use the function in it.
Below is what I already found (it's not correct). I am really stuck here.
public List<Pump> sortedBy(Function<Pump, Comparable<Pump>> function){
List<Pump> sortBy = new ArrayList<Pump>(pumps);
function.apply((Pump) ->Comparator.comparing(pumps::comparator));
Collections.sort(sortBy, Comparator.comparing(function.apply(pumps);
return sortBy;
}
public class Data {
private static List<Pomp> data;
public static List<Pomp> getData() {
data = new ArrayList<>();
data.add(new Pomp("J6706A", 100.0, 2, Aandrijving.TURBINE, LocalDate.of(2022, 1, 10), true, 500.0, "Slurry pomp"));
data.add(new Pomp("J6707A", 55.5, 1, Aandrijving.MOTOR, LocalDate.of(2022, 2, 10), false, 500.0, "Clarified pomp"));
data.add(new Pomp("J6706B", 100.0, 2, Aandrijving.TURBINE, LocalDate.of(2022, 3, 10), true, 500.0, "Slurry pomp"));
data.add(new Pomp("J6706C", 100.0, 2, Aandrijving.TURBINE, LocalDate.of(2022, 4, 10), true, 500.0, "Slurry pomp"));
data.add(new Pomp("J6705A", 62, 1, Aandrijving.MOTOR, LocalDate.of(2022, 5, 10), false, 250, "Voedings pomp"));
data.add(new Pomp("J6705B", 35, 2, Aandrijving.TURBINE, LocalDate.of(2022, 6, 10), false, 150, "Voedings pomp"));
data.add(new Pomp("J6708B", 100.0, 2, Aandrijving.TURBINE, LocalDate.of(2022, 7, 10), false, 300, "HCO circ pomp"));
return data;
}
}
public class Pompen {
private TreeSet<Pomp> pompen = new TreeSet<>();
public void add(Pomp pomp) {
pompen.add(pomp);
}
class VermogenComparator implements Comparator<Pomp> {
@Override
public int compare(Pomp pomp1 , Pomp pomp2) {
return Double.compare(pomp1.getVermogen(), pomp2.getVermogen());
}
}
class RevisieComparator implements Comparator<Pomp> {
@Override
public int compare(Pomp pomp1 , Pomp pomp2) {
return pomp1.getLaatsteRevisie().compareTo(pomp2.getLaatsteRevisie());
}
}
class Zelfontbranding implements Comparator<Pomp> {
@Override
public int compare(Pomp pomp1 , Pomp pomp2) {
return Boolean.compare(pomp1.getBovenZelfOntbranding(), pomp2.getBovenZelfOntbranding());
}
}
Because of your example using sortBy(Pump::getName)
, I believe that the intent here is to use the Comparator.comparing()
factory to create a comparator that extracts a sort key from each object. However, this requires some changes to the generic types used in the prescribed method signature. Working code would look something like this:
public <U extends Comparable<? super U>> List<Pomp> sortedBy(Function<Pomp, ? extends U> toKey) {
List<Pomp> sorted = new ArrayList<>(pompen);
sorted.sort(Comparator.comparing(toKey));
return sorted;
}
This will accept lambdas like Pomp::getNaam
as long as the indicated property is Comparable
:
System.out.println("Pumps sorted on power:");
pompen.sortedBy(Pomp::getVermogen).forEach(System.out::println);
A better design would be to pass a Comparator
; while it's a tiny bit more work for the caller, it gives them full control over the sorting. For example, they can specify a secondary sort key, or reverse the order. Or one could go another step further and simply return a copy of the pumps collection as a list and let the caller do whatever they wish with it.
If permitted, you could change the API to this:
public List<Pomp> sortedBy(Comparator<? super Pomp> order) {
List<Pomp> sorted = new ArrayList<>(pompen);
sorted.sort(order);
return sorted;
}
The caller would then be responsible for creating a Comparator
that meets their need:
/* Like this: */
List<Pomp> sortedByName = pompen.sortedBy(Comparator.comparing(Pomp::getNaam));
/* Or this: */
List<Pomp> pumpsDescendingPower =
pompen.sortedBy(Comparator.comparing(Pomp::getVermogen).reversed());
This approach is more idiomatic for Java.