2

I have below class definition -

    class Employee {

                Long key;
                String initials;
                Integer age;
    }

Below is the definition of IntWrapper class -

    class  IntWrapper {
            private Integer i;
    }

I have collection of Employee objects in a list List<Employee> = ....

Now I want to create a Map<String, Integer> where key is the initial and value is maximum age of employee with that initials.

I achieved this by below logic -

    Map<String, IntWrapper> r2 = empList.stream().collect(Collectors.groupingBy(e -> e.getName(),
                    Collectors.collectingAndThen(Collectors.maxBy(Comparator.nullsLast(Comparator.comparingInt(Employee::getAge))), empOpt -> empOpt.map(x -> new IntWrapper(x.getAge())).orElseGet(() -> null) )));

Everything works fine here when there no employee with null initials. If there, it throws NullPointerException.

I found a solution to groupby with null keys in this SO post https://stackoverflow.com/a/22650233/2541276.

    public static <T, A> Collector<T, ?, Map<A, List<T>>>
        groupingBy_WithNullKeys(Function<? super T, ? extends A> classifier) {
            return Collectors.toMap(
                    classifier,
                    Collections::singletonList,
                    (List<T> oldList, List<T> newEl) -> {
                        List<T> newList = new ArrayList<>(oldList.size() + 1);
                        newList.addAll(oldList);
                        newList.addAll(newEl);
                        return newList;
                    });
        }

Now I don't know how to apply collectors on the resulting values because Collectors.toMap doesn't take collector to apply on the resulting type.

Any help how can I achieve the same?

Naman
  • 27,789
  • 26
  • 218
  • 353
user51
  • 8,843
  • 21
  • 79
  • 158

1 Answers1

2

You can filter null initials then collect as map, if you want to ignore employee with null initials.

Map<String, IntWrapper> result = empList.stream().filter(e -> e.getInitials() != null)
    .collect(Collectors.toMap(e -> e.getInitials(), x -> new IntWrapper(x.getAge()),
        BinaryOperator.maxBy(Comparator.comparing(IntWrapper::getI))));

Or use Optional as map key for null initial as key

Map<Optional<String>, IntWrapper> result = empList.stream().filter(e -> e.getInitials() != null)
        .collect(Collectors.toMap(e -> Optional.ofNullable(e.getInitials()), x -> new IntWrapper(x.getAge()),
            BinaryOperator.maxBy(Comparator.comparing(IntWrapper::getI))));
Eklavya
  • 17,618
  • 4
  • 28
  • 57
  • Yes you are right, just found out when test I don't wrap up thats problem. Updated. Thanks to point out. – Eklavya May 18 '20 at 08:53