Count Elements in a stream and return Integer insted of long

浪子不回头ぞ 提交于 2021-02-19 07:35:08

问题


I need to count Elements in a Stream and assign it to an Integer without casting.

.count() does return long

thought about the .collect(Collectors.reducing(..)) but cant figure it out. I feel like there is something simple I don't get.

My Try:

Stream<String> s = Stream.of("Hallo ", "Test", "String");
Integer count = s.filter(e -> (e.length() >= lb && e.length() <= ub && !e.contains(" ")))
                 .map(e -> e.toUpperCase())
                 .distinct()
                 .collect(Collectors.reducing(0, e -> 1, Integer::sum)));

System.out.println(count);

回答1:


Simply: don't.

Don't cast, but also don't make things overly complicated.

Rather look into safe ways of getting that int out of the long returned by count(). See here for starters:

int bar = Math.toIntExact(someLong);

for example. When you are 100% sure that the computed value always fits within int, then you just avoid putting down the catch for the potentially thrown ArithmeticException. And you still got that good feeling that you can't "overrun" without noticing.

But as said: don't invest time/energy into specially computing your own stuff, when you can use built-in functionality to count things, and turn them into int/Integer. Remember: each character you put into code needs to be read and understood later on. Thus even "20 characters" more add up over time. So when you always lean towards the shorter solution, as long as they are easy to read/understand.




回答2:


Here is the right way. Convert all the distinct values to 1 using Stream::mapToInt - it produces the IntStream which has sum/count methods able to handle stream of numeric values directly without mapping:

Integer count = s.filter(e -> (e.length() >= lb && e.length() <= ub && !e.contains(" ")))
                 .map(String::toUpperCase)
                 .distinct()
                 .mapToInt(i -> 1)
                 .sum();

Without mapping to int, you can use Stream::reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner) to get the very same result:

Integer count = s.filter(e -> (e.length() >= 2 && e.length() <= 10 && !e.contains(" ")))
                 .map(String::toUpperCase)
                 .distinct()
                 .reduce(0, (a,b) -> a + 1, (a,b) -> a + b);

The interface of this method is little bit complicated:

  • U identity is set to 0 - a start of counting
  • accumulator ((a,b) -> a + 1) converts the String to int, each String will be converted to 1 and added to the previous result (0+1+1+1...).
  • combiner combines two consecutive values ((a,b) -> a + b) - the sum of the 1 values, which is practically the count.



回答3:


If you want to count the elements in stream without using the build in .count() method then you could map each element to an int and reduce by summing them. Something like this:

Integer count = s.mapToInt(i -> 1).reduce((a, b) -> a + b).orElse(0);

Or as @Holger commented bellow to use the sum() after mapping.

Integer count = s.mapToInt(i -> 1).sum();



回答4:


With Java 8, you can use Math.toIntExact(long val).

public static int toIntExact(long value)

Returns the value of the long argument; throwing an exception if the value overflows an int.



来源:https://stackoverflow.com/questions/51968025/count-elements-in-a-stream-and-return-integer-insted-of-long

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!