将List<Foo>转List<Bar>时Stream分组后Map操作编译错误排查
问题:List转List分组时Stream map编译错误
尝试将List<Foo>转换为List<Bar>,需要按3个属性分组。先通过Stream将List<Foo>收集为Map<Triple<String, String, String>, List<Foo>>,但在把Map的entrySet转为Stream并map成List<Bar>时出现编译错误:
[javac] /FooBarConversion.java:69: error: incompatible types: inference variable R has incompatible bounds [javac] .map(entry -> { [javac] ^ [javac] upper bounds: Object [javac] lower bounds: void [javac] where R,T are type-variables: [javac] R extends Object declared in method <R>map(Function<? super T,? extends R>) [javac] T extends Object declared in interface Stream [javac] 1 error
我知道这表示map需要返回Object,但实际得到了void,想知道是Collectors.groupingBy用错了还是其他问题,相关代码如下:
import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.commons.lang3.tuple.Triple; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class FooBarConversion { public List<Bar> convertFooToBar(String type, List<Foo> fooList) { Map<Triple<String, String, String>, List<Foo>> fooMap = fooList.stream() .collect( Collectors.groupingBy( foo -> ImmutableTriple.of(foo.getFirstName(), foo.getMiddleName(), foo.getLastName()) ) ); return fooMap.entrySet() // Set<Map<K,V>.Entry<Triple<...>, List<...>>> .stream() // Stream<Map<K,V>.Entry<Triple<...>, List<...>>> .map(entry -> { // 编译错误发生在这里 Triple<String, String, String> key = entry.getKey(); Bar bar = Bar.builder() .withFirstName(key.getLeft()) .withMiddleName(key.getMiddle()) .withLastName(key.getRight()) .build(); // 其他代码 return bar; }).collect(Collectors.toList()); } }
问题分析与解决
这个错误和Collectors.groupingBy完全无关,分组逻辑是正确的。问题出在你注释掉的// 其他代码部分。
编译错误提示的“lower bounds: void”,本质是你传给map的lambda表达式实际返回了void,但Stream.map要求传入的Function必须返回一个非void的类型(对应泛型参数R),这就导致了类型不匹配。
可能的原因:
- lambda代码块最后一行是void方法调用:如果在
// 其他代码区域,你最后执行的是一个返回void的方法(比如bar.someVoidMethod()),且没有显式写return bar;,lambda就会返回void。 - 存在无返回值的代码路径:比如你在代码里加了if/else分支,某个分支没有返回
Bar实例(比如忘记写return语句)。
解决方法:
检查// 其他代码区域的逻辑,确保所有代码路径最终都返回Bar类型的实例。比如确保lambda代码块的最后一行是return bar;,或者直接返回Bar实例的表达式。
举个反例,下面的代码就会触发这个错误:
.map(entry -> { Triple<String, String, String> key = entry.getKey(); Bar bar = Bar.builder()...build(); bar.setSomeProperty(); // 这是void方法,成为lambda的返回值 // 忘记写return bar; })
只要修正lambda的返回值逻辑,确保它始终返回Bar实例,这个编译错误就会消失。
内容的提问来源于stack exchange,提问作者Torc
相关产品推荐
相关产品推荐

