[英]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.