artmmslv
artmmslv

Reputation: 149

Count Java Stream to Integer, not Long

I need to count occurences of some special bundles.

Map<Integer,Integer> countBundles(){
    return bundles.stream()
        .bla()
        .bla()
        .bla()
        .collect(groupingBy(Bundle::getId), counting()));
}

This code does not compile because counting returns Long. Is there any beautiful way to return Map<Integer, Integer>?

I have this idea, but it`s ugly

  map.entrySet().stream()
     .collect(toMap(Map.Entry::getKey, entry -> (int) entry.getValue().longValue()));

Upvotes: 3

Views: 3392

Answers (2)

Hoopje
Hoopje

Reputation: 12932

You can use Collectors.collectingAndThen to apply a function to the result of your Collector:

Map<Integer,Integer> countBundles() {
    return bundles.stream()
        .bla()
        .bla()
        .bla()
        .collect(groupingBy(Bundle::getId, collectingAndThen(counting(), Long::intValue)));
}

If you need some other semantics than just a cast, replace Long::intValue with some other conversion code.

Upvotes: 10

Glains
Glains

Reputation: 2863

There is no build-in way to use Collectors.counting() with Integer, since generics are invariant. However, you can write a custom Collector with minimal effort:

public static <T> Collector<T, ?, Integer> countingInt() {
    return Collectors.summingInt(e -> 1);
}

You can also use the plain summingInt(e -> 1) if you want to use native libraries only.

Example:

Map<Integer,Integer> countBundles(){
    return bundles.stream()
        .bla()
        .bla()
        .bla()
   // 1 .collect(groupingBy(Bundle::getId), countingInt()));
   // 2 .collect(groupingBy(Bundle::getId), summingInt(e -> 1)));
}

Please note that with signed interpretation, you can count at most 2.147.483.647 elements.

Upvotes: 5

Related Questions