Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Streams: Issue about collect to a Map<String, Object>

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>
like image 869
Jordi Avatar asked Nov 12 '18 12:11

Jordi


People also ask

How do I collect a stream map?

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.

Can we use stream with map in Java?

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.

What is the purpose of the map method in Java 8 streams?

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.

Why do we use map in streams?

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.


2 Answers

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);
like image 121
Eran Avatar answered Oct 16 '22 02:10

Eran


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 Arguments 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));
}
like image 33
Magnilex Avatar answered Oct 16 '22 02:10

Magnilex