java 8 中的类型不匹配错误
Type mismatch error in java 8
我有以下 class 使用以下方法。
public class MyClass {
public static <T> T getSomeThing(final int id, final java.lang.reflect.Type type, final Map<Integer, String> someThings) {
final String aThing = someThings.get(id);
if (aThing == null || aThing.isEmpty()) {
return null;
}
return GsonHelper.GSON.fromJson(aThing, type);
}
}
GsonHelper 为我提供了一些 com.google.gson.GsonBuilder
public class GsonHelper {
public static final com.google.gson.Gson GSON = getGsonBuilder().create();
public static GsonBuilder getGsonBuilder() {
return new GsonBuilder().setPrettyPrinting()
.enableComplexMapKeySerialization()
.registerTypeAdapter(new com.google.gson.reflect.TypeToken.TypeToken<byte[]>() {
// no body
}.getType(), new Base64TypeAdapter())
.registerTypeHierarchyAdapter(Date.class, new DateTypeAdapter())
.registerTypeHierarchyAdapter(Pattern.class, new PatternTypeAdapter())
.registerTypeAdapterFactory(new ListTypeAdapterFactory())
.registerTypeAdapterFactory(new MapTypeAdapterFactory())
.registerTypeAdapterFactory(new SetTypeAdapterFactory());
}
}
直到 Java 7 我使用的方法如下:
Map<Integer, String> allThings = new HashMap<>();
//FILL allThings with values
if(MyClass.getSomeThing(7, java.lang.Boolean.class, allThings)){
//do something
}
这很好用。因为该方法将 return 一个布尔值,我可以在 "if" 中使用它。但是当我更改为 Java 8 时,这就不可能了。
编译器抱怨:
Type mismatch: cannot convert from Object to boolean
//while this is working but would throw a JsonSyntaxException
final String myString = "myInvalidJsonString";
if(GsonHelper.GSON.fromJson(myString, java.lang.Boolean.class)){
//do something
}
我知道 java.lang.Boolean 可以为空。我可以通过以下方式解决这个问题:
final Boolean b = MyClass.getSomeThing(7, java.lang.Boolean.class, allThings);
if(b){
//do something
}
但我很好奇为什么这适用于 Java 7 而不是 Java 8。(未回答)
他们改变了什么? (未回答)
更改为 Java 8 时出现此编译器错误的原因是什么? (已回答)
您的方法 public static <T> T getSomeThing(final int id, final java.lang.reflect.Type t, final Map<Integer, String> someThings)
不能保证 return 一个 Boolean
。它 returns T
由调用者定义,可以是任何东西,这意味着 Object
.
if 语句 无法知道 T
将具有哪种类型,因此不能保证将其转换为布尔值。
为什么不将签名更改为布尔值?
public static boolean getSomeThing(final int id,
final java.lang.reflect.Type t,
final Map<Integer, String> someThings)
或者您正在寻找这个?
public static <T> T getSomeThing(final int id,
final Class<T> clazz,
final Map<Integer, String> someThings)
此代码将编译并运行:
public static void main(String[] args) {
if (getSomeThing(7, Boolean.class, emptyMap())) {
System.out.println("It works!");
}
}
public static <T> T getSomeThing(final int id,
final Class<T> clazz,
final Map<Integer, String> someThings) {
...
}
可以根据 JLS 8 推断 getSomeThing()
的结果分配给 Boolean
变量的最后一个版本,因为在 分配上下文中 目标类型 Boolean
确实可以将 T
推断为 Boolean
。这里所有的编译器都同意。
关于原始情况,JLS 8 没有将 if 语句的条件分类为 赋值上下文 。在赋值或调用上下文之外,调用不被视为多边形表达式,而是被视为独立表达式 (JLS 15.12 1st bullet)。独立表达式没有目标类型。在 Java 中没有目标类型推断 8 退回到推断 T
到 Object
.
Eclipse 团队 requested clarification in this regard even before Java 8 GA. Unfortunately, the resulting issue 直到今天仍未解决。
因此:JLS 和观察到的 javac
行为似乎并不一致。 很可能,JLS 是应该修复的实体。
更新: JLS 不会更改(通过私人电子邮件确认),因此接受该程序是 javac
.
中的错误
编辑: Javac 版本 12 甚至会通过开关表达式传播此错误:
public class X {
@SuppressWarnings("preview")
public void foo(int i) {
if (switch(i) { default -> magic(); })
System.out.println("true");
}
<T> T magic() { return null; }
}
由于目标类型 Boolean
的类型推断,javac 接受了这一点,但根据 JLS,在此位置执行类型推断是非法的。
我有以下 class 使用以下方法。
public class MyClass {
public static <T> T getSomeThing(final int id, final java.lang.reflect.Type type, final Map<Integer, String> someThings) {
final String aThing = someThings.get(id);
if (aThing == null || aThing.isEmpty()) {
return null;
}
return GsonHelper.GSON.fromJson(aThing, type);
}
}
GsonHelper 为我提供了一些 com.google.gson.GsonBuilder
public class GsonHelper {
public static final com.google.gson.Gson GSON = getGsonBuilder().create();
public static GsonBuilder getGsonBuilder() {
return new GsonBuilder().setPrettyPrinting()
.enableComplexMapKeySerialization()
.registerTypeAdapter(new com.google.gson.reflect.TypeToken.TypeToken<byte[]>() {
// no body
}.getType(), new Base64TypeAdapter())
.registerTypeHierarchyAdapter(Date.class, new DateTypeAdapter())
.registerTypeHierarchyAdapter(Pattern.class, new PatternTypeAdapter())
.registerTypeAdapterFactory(new ListTypeAdapterFactory())
.registerTypeAdapterFactory(new MapTypeAdapterFactory())
.registerTypeAdapterFactory(new SetTypeAdapterFactory());
}
}
直到 Java 7 我使用的方法如下:
Map<Integer, String> allThings = new HashMap<>();
//FILL allThings with values
if(MyClass.getSomeThing(7, java.lang.Boolean.class, allThings)){
//do something
}
这很好用。因为该方法将 return 一个布尔值,我可以在 "if" 中使用它。但是当我更改为 Java 8 时,这就不可能了。 编译器抱怨:
Type mismatch: cannot convert from Object to boolean
//while this is working but would throw a JsonSyntaxException
final String myString = "myInvalidJsonString";
if(GsonHelper.GSON.fromJson(myString, java.lang.Boolean.class)){
//do something
}
我知道 java.lang.Boolean 可以为空。我可以通过以下方式解决这个问题:
final Boolean b = MyClass.getSomeThing(7, java.lang.Boolean.class, allThings);
if(b){
//do something
}
但我很好奇为什么这适用于 Java 7 而不是 Java 8。(未回答)
他们改变了什么? (未回答)
更改为 Java 8 时出现此编译器错误的原因是什么? (已回答)
您的方法 public static <T> T getSomeThing(final int id, final java.lang.reflect.Type t, final Map<Integer, String> someThings)
不能保证 return 一个 Boolean
。它 returns T
由调用者定义,可以是任何东西,这意味着 Object
.
if 语句 无法知道 T
将具有哪种类型,因此不能保证将其转换为布尔值。
为什么不将签名更改为布尔值?
public static boolean getSomeThing(final int id,
final java.lang.reflect.Type t,
final Map<Integer, String> someThings)
或者您正在寻找这个?
public static <T> T getSomeThing(final int id,
final Class<T> clazz,
final Map<Integer, String> someThings)
此代码将编译并运行:
public static void main(String[] args) {
if (getSomeThing(7, Boolean.class, emptyMap())) {
System.out.println("It works!");
}
}
public static <T> T getSomeThing(final int id,
final Class<T> clazz,
final Map<Integer, String> someThings) {
...
}
可以根据 JLS 8 推断 getSomeThing()
的结果分配给 Boolean
变量的最后一个版本,因为在 分配上下文中 目标类型 Boolean
确实可以将 T
推断为 Boolean
。这里所有的编译器都同意。
关于原始情况,JLS 8 没有将 if 语句的条件分类为 赋值上下文 。在赋值或调用上下文之外,调用不被视为多边形表达式,而是被视为独立表达式 (JLS 15.12 1st bullet)。独立表达式没有目标类型。在 Java 中没有目标类型推断 8 退回到推断 T
到 Object
.
Eclipse 团队 requested clarification in this regard even before Java 8 GA. Unfortunately, the resulting issue 直到今天仍未解决。
因此:JLS 和观察到的 javac
行为似乎并不一致。 很可能,JLS 是应该修复的实体。
更新: JLS 不会更改(通过私人电子邮件确认),因此接受该程序是 javac
.
编辑: Javac 版本 12 甚至会通过开关表达式传播此错误:
public class X {
@SuppressWarnings("preview")
public void foo(int i) {
if (switch(i) { default -> magic(); })
System.out.println("true");
}
<T> T magic() { return null; }
}
由于目标类型 Boolean
的类型推断,javac 接受了这一点,但根据 JLS,在此位置执行类型推断是非法的。