I have the following code
public static List<Integer> topKFrequent(int[] nums, int k) {
List<Integer> myList = new ArrayList<>();
HashMap<Integer, Integer> map = new HashMap<>();
for (int n : nums) {
if (!map.containsKey(n)) map.put(n, 1);
else map.put(n, map.get(n) + 1);
}
map.entrySet().stream()
.sorted(Map.Entry.<Integer, Integer>comparingByValue().reversed())
.limit(k)
.forEach((key, value) -> myList.add(key));
return myList;
}
The forEach
throws the error
Error:(20, 16) java: incompatible types: incompatible parameter types in lambda expression
How can I fix/avoid this error? I'm not quite sure how to apply the answer here that explains the problem: Lambda Expression and generic method
Edit:
Given the answer, the correction is to replace the lambda inside the forEach with
.forEach((entry) -> myList.add(entry.getKey()));
Optional type declaration − No need to declare the type of a parameter. The compiler can inference the same from the value of the parameter. Optional parenthesis around parameter − No need to declare a single parameter in parenthesis. For multiple parameters, parentheses are required.
Type Inference means that the data type of any expression (e.g. method return type or parameter type) can be deduced automatically by the compiler. Groovy language is a good example of programming languages supporting Type Inference. Similarly, Java 8 Lambda expressions also support Type inference.
No, there isn't. Lambda expressions are optimised (in terms of syntax) for the single parameter case. I know that the C# team feels your pain, and have tried to find an alternative.
Basically to pass a lamda expression as a parameter, we need a type in which we can hold it. Just as an integer value we hold in primitive int or Integer class. Java doesn't have a separate type for lamda expression instead it uses an interface as the type to hold the argument.
entrySet()
returns a set of Pair<K, V>
.
forEach()
's lambda therefore takes a single parameter of that type; not two integer parameters.
You are going about it in a java7-ish way. Modifying external data structures from inside forEach
is not how Streams API was meant to be used. Streams API documentation specifically warns against such use in the Side-Effects section of java.util.stream
package summary
Instead of appending to list or map from inside forEach
, use collect
:
import static java.util.Comparator.reverseOrder;
import static java.util.Map.Entry.comparingByValue;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
public static List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer, Long> freq = Arrays.stream(nums).boxed()
.collect(groupingBy(x->x, counting()));
return freq.entrySet()
.stream()
.sorted(comparingByValue(reverseOrder()))
.limit(k)
.map(Map.Entry::getKey)
.collect(toList());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With