我最近更新了我的Android Studio 3项目。我想支持 Java 8 语言功能,因此在 build.gradle 中添加了以下内容:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
然后,我在 Android 8.0.0 设备上运行我的应用。在运行时我看到
java.lang.NoSuchMethodError: No virtual method keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView; in class Ljava/util/concurrent/ConcurrentHashMap; or its super classes (declaration of 'java.util.concurrent.ConcurrentHashMap' appears in /system/framework/core-oj.jar)
我认为这与以下事实有关:Java 8 中keySet()
的签名已从返回Set<K>
更改为返回KeySetView<K,V>
。
导致异常的行如下所示:
for (Long id : mSomeMap.keySet())
KeySetView
实现了Set
,它肯定是Iterable
,所以无论这一行被解释为 Java 7 还是 Java 8,我都会认为它会以任何一种方式工作。我对Java基础知识的理解是粗略的 - 这是怎么回事?
更新
到目前为止,我的片状理解是这样的:
虽然Android现在支持一些Java 8语言功能,但其API与Java 8并不相同。特别是 Android 的ConcurrentHashMap.keySet()
实现返回一个Set
,而 Java 8
ConcurrentHashMap.keySet()
返回一个KeySetView
。不知何故,Android Studio 设法使用标准 Java 8 JDK 编译我的应用程序,因此在运行时希望找到一种带有签名KeySetView<K,V> keySet()
的方法。但是,Android的ConcurrentHashMap
没有具有此签名的方法,因此我得到了NoSuchMethodError
。
我还没有弄清楚Android Studio如何或为什么使用不兼容的JDK进行构建。在项目结构中,选中了"使用嵌入式JDK(推荐(",因此我假设Android Studio正在使用与之捆绑的JDK进行构建。
不是解决方案
到目前为止,大多数评论/答案都指出,我可以将ConcurrentHashMap
声明为解决此问题Map
。这是一种解决方法,而不是解决方案。如果根本问题是我的应用程序是使用错误的 JDK 构建的,那么可能存在方法签名分歧的其他情况,并且由于我无法在大型项目中实时测试 100% 的代码路径,因此我无法保证在运行时不会抛出更多NoSuchMethodErrors
。
我正在使用此解决方法,似乎正在工作。
private final Map<ImageView, Request> mPendingRequests =
new ConcurrentHashMap<ImageView, Request>();
只是将其转换为Map<?, ?>
:
for (Long id : ((Map< Long, ?>)mSomeMap).keySet())
您正在使用 ConcurrentHashMap 的特殊实现
'java.util.concurrent.ConcurrentHashMap' 的声明出现在/system/framework/core-oj.jar
没有方法keySet()
你可以声明ConcurrentMap
接口:
ConcurrentMap mSomeMap = new ConcurrentHashMap();
然后像这样使用:
for (Long id : mSomeMap.keySet())