java 8 兼容,Java 8不兼容的类型

Here's the simple code

import java.util.ArrayList;

import java.util.Collections;

import java.util.HashMap;

import java.util.Map;

public class SimpleTest {

public static void main(String[] args) {

final ArrayList> maps = newArrayList(

createMap("1", "a", Collections.EMPTY_MAP, Collections.EMPTY_MAP),

createMap("2", "b", Collections.EMPTY_MAP, Collections.EMPTY_MAP),

createMap("3", "c", Collections.EMPTY_MAP, Collections.EMPTY_MAP)

);

System.out.println(" maps = " + maps);

}

public static Map createMap(String value1, String value2, Map object1, Map object2) {

Map map = new HashMap<>();

map.put("value1", value1);

map.put("value1", value1);

map.put("object1", object1);

map.put("object2", object2);

return map;

}

public static ArrayList newArrayList(E... elements) {

ArrayList list = new ArrayList(elements.length);

Collections.addAll(list, elements);

return list;

}

}

When JAVA_HOME points to JDK 8 and I use javac -source 1.7 SimpleTest.java I get

SimpleTest.java:9: error: incompatible types: ArrayList cannot be converted to ArrayList>

final ArrayList> maps = newArrayList(

^

When I use -source 1.8 or no -source option everything works ok. Now, when JAVA_HOME points to JDK 7 the code always compiles whether I use -source 1.7 or not.

Initially this question was about a piece of software where POM file has a and set to 1.7 and the build was failing on JDK 8 but was ok on JDK 7.

Now for the question - what causes it to happen ? It seems to me as a major overlook of some sort. Why compiling on JDK 8 with source set to 1.7 fails ?

解决方案

You can simplify the code to a self-contained example which doesn’t need 3rd-party libraries:

public class Test2 {

@SafeVarargs

static ArrayList newArrayList(T... arg) {

return new ArrayList(Arrays.asList(arg));

}

private final List> maps = newArrayList(

createMap(null, Collections.EMPTY_MAP)

);

public static Map createMap(String id, Map m) {

return null;

}

}

This can be compiled using javac from jdk1.7, but not with javac from jdk1.8 using -source 1.7.

The point here is that javac from jdk1.8 still is a different compiler than the one included in the previous version and the option -source 1.7 doesn’t tell it to mimic the old implementation’s behavior but to be compatible with the Java 7 specification. If the old compiler has a bug, the newer compiler doesn’t have to try to reproduce the bug.

Since the code uses Collections.EMPTY_MAP rather than Collections.emptyMap(), the raw type Map will be passed to createMap, making it an unchecked invocation having the raw result type Map.

This is mandated by JLS §15.12.2.6:

The result type of the chosen method is determined as follows:

If the chosen method is declared with a return type of void, then the result is void.

Otherwise, if unchecked conversion was necessary for the method to be applicable, then the result type is the erasure (§4.6) of the method's declared return type.

It seems that this behavior has not been (fully) implemented in javac of jdk1.7. Interestingly, it will do it correctly when adding a type parameter like

public static Map createMap(String id, Map m)

making it a generic method. Then, jdk1.7 will produce the same error. But the cited rule applies to all method invocations.

In contrast, the fact that compiling it with Java 8 compliance succeeds stems from the new target type inference, which has entirely different rules.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值