I'm running against an issue:
I've created this stream I need to map to a Map<String, Object>
:
private Map<String, Object> collectArguments(JoinPoint point) {
CodeSignature signature = (CodeSignature) point.getSignature();
String[] argNames = signature.getParameterNames();
Object[] args = point.getArgs();
return IntStream.range(0, args.length)
.collect(Collectors.toMap(param -> argNames[param], param -> args[param]));
}
I'm getting the following message, which I don't quite figure out:
[Java] Type mismatch: cannot convert from Collector<Object,capture#3-of ?,Map<Object,Object>> to Supplier<R>
Method 1: Using Collectors.toMap() Function The Collectors. toMap() method takes two parameters as the input: KeyMapper: This function is used for extracting keys of the Map from stream value. ValueMapper: This function used for extracting the values of the map for the given key.
Converting only the Value of the Map<Key, Value> into Stream: This can be done with the help of Map. values() method which returns a Set view of the values contained in this map. In Java 8, this returned set can be easily converted into a Stream of key-value pairs using Set. stream() method.
Java 8 Stream's map method is intermediate operation and consumes single element forom input Stream and produces single element to output Stream. It simply used to convert Stream of one type to another.
The map() function is a method in the Stream class that represents a functional programming concept. In simple words, the map() is used to transform one object into another by applying a function. That's the reason the Stream. map(Function mapper) takes a function as an argument.
IntStream
doesn't have a collect
method that accepts a Collector
. It only has a 3 argument collect
method having this signature:
<R> R collect(Supplier<R> supplier,
ObjIntConsumer<R> accumulator,
BiConsumer<R, R> combiner)
Perhaps you should use a Stream<Integer>
:
return IntStream.range(0, args.length)
.boxed()
.collect(Collectors.toMap(param -> argNames[param],
param -> args[param]));
Or, if you wish to use the collect
method of IntStream
, it would look like this:
return IntStream.range(0, args.length)
.collect(HashMap::new,
(m,i)->m.put(argNames[i],args[i]),
(m1,m2)->m1.putAll (m2));
or
return IntStream.range(0, args.length)
.collect(HashMap::new,
(m,i)->m.put(argNames[i],args[i]),
Map::putAll);
An alternative to Eran's answer (in which the first variant, to use a Stream<Integer>
is really neat) would be to first map the content of the arrays to an object:
public class Argument {
private final String argName;
private final Object arg;
public Argument(String argName, Object arg) {
this.argName = argName;
this.arg = arg;
}
public String getArgName() {
return argName;
}
public Object getArg() {
return arg;
}
}
The code for collecting this object to a map becomes a very clear and concise basic stream:
Map<String, Object> map = IntStream.range(0, args.length)
.mapToObj(i -> new Argument(argNames[i], args[i]))
.collect(Collectors.toMap(Argument::getArgName, Argument::getArg));
Perhaps even extract the logic for creating Argument
s into its own method:
private List<Argument> toArguments(JoinPoint point) {
String[] argNames = ((CodeSignature) point.getSignature()).getParameterNames();
return IntStream.range(0, point.getArgs().length)
.mapToObj(i -> new Argument(argNames[i], point.getArgs()[i]))
.collect(Collectors.toList());
}
Doing this, your collectArguments()
method would be a simple one-liner:
private Map<String, Object> collectArguments(JoinPoint point) {
return toArguments(point).stream().collect(toMap(Argument::getArgName, Argument::getArg));
}
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