简体   繁体   中英

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>

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));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM