Relatively new to java streams and I have encountered an issue which I could not find a solution for.
I have A list of 10 objects and filtered them to return 4 objects.
List<MyObject> objects.stream() .filter(x -> x.getFlag == 1) .filter(x -> x.amount != null) .collect(Collectors.toList());
this returns 4 objects:
OBJECT 1: {stageNumber = 2, stageToCalc = 1} OBJECT 2: {stageNumber = 5, stageToCalc = 1} OBJECT 3: {stageNumber = 9, stageToCalc = 7} OBJECT 4: {stageNumber = 10, stageToCalc = 7}
So basically what I am trying to do is take stages that have the same value of stageToCalc and find the maximium stageNumber.
E.G: object 3 and object 4 have the same stageToCalc = 7, maximum value according to stage number should return Object 4: {stageNumber = 10, stageToCalc = 7} which is the higher value.
however, my issue comes when I need to get 2 (or more since it might be dynamic). in this case :
it should return object 2 and Object 4.
I have tried using:
objects.stream() .collect(groupingBy(Function.identity(), TreeMap::new, toList()) .lastEntry() .getValue() .forEach(System.out::println)
This will just result in a classCastException
, and if I Use .max()
it would not compile.
I could easy accomplish this in an expensive way with some for loops etc.
however I wonder if there is a way in using just 1 stream iteration.
Hope I am clear on this question. Still new and learning.
THANKS.
Advertisement
Answer
You can use Collectors.groupingBy()
with a downstream Collectors.maxBy()
to get the appropriate objects (With Collectors.collectAndThen()
to pull them out of the Optional
values returned by maxBy()
):
import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; public class Demo { private record MyObject(int stageNumber, int stageToCalc) {} public static void main(String[] args) { List<MyObject> objects = List.of(new MyObject(2, 1), new MyObject(5, 1), new MyObject(9, 7), new MyObject(10, 7));; List<MyObject> maximums = new ArrayList<>(objects.stream() .collect(Collectors.groupingBy(MyObject::stageToCalc, Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(MyObject::stageNumber)), Optional::orElseThrow))) .values()); System.out.println(maximums); } }
will print out
[MyObject[stageNumber=5, stageToCalc=1], MyObject[stageNumber=10, stageToCalc=7]]