This question is related to another I posted a short while ago.
I have figured out a way to group my data the way I want. But because of how I need to group/map the objects I've already closed the stream during collection when I need to apply some filtering. I have the following code:
final Map<TeamDetails, List<Player>> teamDetailsPlayerListMap = dbRows.stream().map(row -> mapDbRowToTeamPlayerPair(row)) .collect(Collectors.groupingBy(TeamPlayerPair::getKey, Collectors.mapping(TeamPlayerPair::getValue, Collectors.toList()))); final List<Team> teams = teamDetailsPlayerListMap.entrySet().stream() .map(teamPlayerList -> mapTeamPlayerListToTeam(teamPlayerList)) .collect(Collectors.toList()); The problem I have is that some dbRows have an empty or null String for the playerName. I don't wan't to filter before collection as if a Team has no players (eg. only 1 db row with empty string as player name), I still want to have that in my list of Teams at the end. It will just have an empty player list.
Is there any way that I can apply a filter during collection so that empty or null strings will not be added to the list???
I have been able to achieve it with a custom collector as shown below but I'm just wondering if there is a way I can do it without a custom collector???
Function<Player, Boolean> emptyPlayerNameFilter = new Function<Player, Boolean>() { @Override public Boolean apply(Player player) { return player != null && player.getName() != null && !"".equals(player.getName()); } }; final Map<TeamDetails, List<Player>> teamDetailsPlayerListMap = dbRows.stream().map(row -> mapDbRowToTeamPlayerPair(row)) .collect(Collectors.groupingBy(TeamPlayerPair::getKey, Collectors.mapping(TeamPlayerPair::getValue, MyCollectors.toFilteredLinkedList(emptyPlayerNameFilter)))); final List<Team> finalTeams = teamDetailsPlayerListMap.entrySet().stream() .map(teamPlayerList -> mapTeamPlayerListToTeam(teamPlayerList)) .collect(Collectors.toList()); Where MyCollectors.toFilteredLinkedList() is:
public class MyCollectors { public static <T, A extends Collection<T>> Collector<T, ?, A> toFilteredCollection(Supplier<A> collectionFactory, Function<T, Boolean> filter) { return Collector.of( collectionFactory, (acc, entry) -> { if (filter.apply(entry)) { acc.add(entry); } }, (left, right) -> { left.addAll(right); return left; } ); } public static <T> Collector<T, ?, List<T>> toFilteredLinkedList(Function<T, Boolean> filter) { return toFilteredCollection(LinkedList<T>::new, filter); } }