[英]Java Stream Generics Type Mismatch
在操作Java 8流时,我遇到了一个错误,编译器似乎“忘记”了我的泛型参数的类型。
以下代码段创建了一个类名流,并尝试将流映射到Class<? extends CharSequence>
Class<? extends CharSequence>
。
public static Stream<Class<? extends CharSequence>> getClasses() {
return Arrays.asList("java.lang.String", "java.lang.StringBuilder", "Kaboom!")
.stream()
.map(x -> {
try {
Class<?> result = Class.forName(x);
return result == null ? null : result.asSubclass(CharSequence.class);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
})
//.filter(x -> x != null)
;
}
当我取消注释过滤器以从流中删除空条目时,我得到编译错误
类型不匹配:无法转换为Class <capture#15-of? 将CharSequence>扩展为Class <Object>
有人可以向我解释为什么添加过滤器会导致此错误吗?
PS:这里的代码有些随意,很容易让错误消失:在应用过滤器之前将映射流分配给临时变量。 我感兴趣的是为什么上面的代码片段会产生编译时错误。
编辑:正如@Holger所指出的那样,这个问题并不完全与Java 8 Streams重复:为什么Collectors.toMap对于带有通配符的泛型有不同的行为? 因为那里有问题的片段目前编译没有问题,而这里的片段没有。
这是因为类型推断:
该类型是从它的目标“猜测”的:我们知道map(任何东西)必须返回"Stream<Class<? extends CharSequence>>"
因为它是函数的返回类型。 如果你链接返回到另一个操作,例如过滤器或地图,我们会松开这种类型推断(它不能“通过”链接)
类型推断有其局限性,您可以找到它。
解决方案很简单:如果你使用变量,你可以指定目标然后帮助类型推断。
这个编译:
public static Stream<Class<? extends CharSequence>> getClasses() {
Stream<Class<? extends CharSequence>> map1 = Arrays.asList ("java.lang.String", "java.lang.StringBuilder", "Kaboom!").stream ().map (x -> {
try {
Class<?> result = Class.forName (x);
return result == null ? null : result.asSubclass(CharSequence.class);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace ();
}
return null;
});
return map1.filter(x -> x != null);
请注意,我修改了代码以返回始终为null,以显示不同的类型不是来自lambda返回类型。
我们看到map1的类型受变量声明的影响,它的目标。 如果我们返回它,它是等价的,目标是返回类型,但如果我们链接它:
这不编译:
public static Stream<Class<? extends CharSequence>> getClasses () {
return Arrays.asList ("java.lang.String", "java.lang.StringBuilder", "Kaboom!").stream ().map (x -> {
try {
Class<?> result = Class.forName (x);
return result == null ? null : result.asSubclass(CharSequence.class);
} catch (Exception e) {
e.printStackTrace ();
}
return null;
}).filter(x -> x != null);
第一个映射声明没有目标,因此默认情况下定义了impred类型: Stream<Object>
编辑
使其工作的另一种方法是使类型推断使用Lambda返回值(而不是目标),您需要指定带有强制转换的返回类型。 这将编译:
public static Stream<Class<? extends CharSequence>> getClasses2 () {
return Arrays.asList ("java.lang.String", "java.lang.StringBuilder", "Kaboom!").stream ().map (x -> {
try {
Class<?> result = Class.forName (x);
return (Class<? extends CharSequence>)( result == null ? null : result.asSubclass(CharSequence.class));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace ();
}
return (Class<? extends CharSequence>)null;
}).filter(x -> x != null);
}
请注意,这是因为操作链接,你可以用map(x-> x)替换.filter(x - > x!= null)你会遇到同样的问题。
编辑:修改示例以完全匹配问题。
除了@pdem的答案 ,这也适合你:
public class Test {
public static void main(String[] args) {
getAsSubclasses(CharSequence.class, "java.lang.String", "java.lang.StringBuilder", "Kaboom!")
.forEach(System.out::println);
}
public static <C> Stream<Class<? extends C>> getAsSubclasses(Class<C> type, String... classNames) {
return Arrays.stream(classNames)
.map(new ToSubclass<>(type))
.filter(c -> c != null);
}
static final class ToSubclass<C> implements Function<String, Class<? extends C>> {
final Class<C> type;
ToSubclass(Class<C> type) {
this.type = type;
}
@Override
public Class<? extends C> apply(String s) {
try {
return Class.forName(s).asSubclass(type);
} catch (Exception e) {
return null;
}
}
}
}
因为无法确定lambda函数的返回类型(或编译器只是不尝试这样做)。 使用具有正确类型参数的显式匿名Function
对象可以完全消除类型推断的问题:
public static Stream<Class<? extends CharSequence>> getClasses() {
return Arrays.asList("java.lang.String",
"java.lang.StringBuilder",
"Kaboom!")
.stream().map(
new Function<String, Class<? extends CharSequence>>() {
public Class<? extends CharSequence> apply(String name) {
try {
return Class.forName(name).asSubclass(CharSequence.class);
} catch (Exception e) {
}
return null;
}
}
).filter(Objects::nonNull);
}
要看,编译器解决了lambda函数的实际返回类型,请尝试让Eclipse将表达式...stream().map(<your initial lambda>)
分配给局部变量(按Ctrl+2
,然后用光标L
站在表达之前)。 它是Stream<Class<? extends Object>>
Stream<Class<? extends Object>>
返回类型由编译器解析,而不是预期的Stream<Class<? extends CharSequence>>
Stream<Class<? extends CharSequence>>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.